/*
* Created on 20-Dec-2005
* Created by Paul Gardner
* Copyright (C) 2005, 2006 Aelitis, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* AELITIS, SAS au capital de 46,603.30 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/
package com.aelitis.azureus.core.instancemanager.impl;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.util.*;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.config.ParameterListener;
import org.gudy.azureus2.core3.download.DownloadManager;
import org.gudy.azureus2.core3.logging.LogEvent;
import org.gudy.azureus2.core3.logging.LogIDs;
import org.gudy.azureus2.core3.logging.Logger;
import org.gudy.azureus2.core3.torrent.TOTorrent;
import org.gudy.azureus2.core3.util.AEMonitor;
import org.gudy.azureus2.core3.util.AERunnable;
import org.gudy.azureus2.core3.util.AESemaphore;
import org.gudy.azureus2.core3.util.AEThread;
import org.gudy.azureus2.core3.util.BDecoder;
import org.gudy.azureus2.core3.util.BEncoder;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.DelayedEvent;
import org.gudy.azureus2.core3.util.SHA1Simple;
import org.gudy.azureus2.core3.util.SimpleTimer;
import org.gudy.azureus2.core3.util.SystemTime;
import org.gudy.azureus2.core3.util.TimerEvent;
import org.gudy.azureus2.core3.util.TimerEventPerformer;
import org.gudy.azureus2.plugins.download.Download;
import org.gudy.azureus2.pluginsimpl.local.download.DownloadManagerImpl;
import com.aelitis.azureus.core.AzureusCore;
import com.aelitis.azureus.core.AzureusCoreLifecycleAdapter;
import com.aelitis.azureus.core.instancemanager.AZInstance;
import com.aelitis.azureus.core.instancemanager.AZInstanceManager;
import com.aelitis.azureus.core.instancemanager.AZInstanceManagerListener;
import com.aelitis.azureus.core.instancemanager.AZInstanceTracked;
import com.aelitis.azureus.core.util.NetUtils;
import com.aelitis.net.udp.mc.MCGroup;
import com.aelitis.net.udp.mc.MCGroupAdapter;
import com.aelitis.net.udp.mc.MCGroupFactory;
public class
AZInstanceManagerImpl
implements AZInstanceManager, MCGroupAdapter
{
private static final boolean DISABLE_LAN_LOCAL_STUFF = false;
static{
if ( DISABLE_LAN_LOCAL_STUFF ){
System.out.println( "**** LAN LOCAL STUFF DISABLED ****" );
}
}
private static final LogIDs LOGID = LogIDs.NET;
private String MC_GROUP_ADDRESS = "239.255.067.250"; // 239.255.000.000-239.255.255.255
private int MC_GROUP_PORT = 16680; //
private int MC_CONTROL_PORT = 0;
private static final int MT_VERSION = 1;
private static final int MT_ALIVE = 1;
private static final int MT_BYE = 2;
private static final int MT_REQUEST = 3;
private static final int MT_REPLY = 4;
private static final int MT_REQUEST_SEARCH = 1;
private static final int MT_REQUEST_TRACK = 2;
private static final long ALIVE_PERIOD = 30*60*1000;
private static AZInstanceManagerImpl singleton;
private List listeners = new ArrayList();
private static AEMonitor class_mon = new AEMonitor( "AZInstanceManager:class" );
private static String socks_proxy = null;
static{
COConfigurationManager.addAndFireParameterListeners(
new String[]{ "Proxy.Data.Enable", "Proxy.Host", "Proxy.Data.Same", "Proxy.Data.Host" },
new ParameterListener()
{
public void
parameterChanged(
String parameterName )
{
if ( !COConfigurationManager.getBooleanParameter("Proxy.Data.Enable")){
socks_proxy = null;
return;
}
if ( COConfigurationManager.getBooleanParameter("Proxy.Data.Same")){
socks_proxy = COConfigurationManager.getStringParameter( "Proxy.Host" );
}else{
socks_proxy = COConfigurationManager.getStringParameter( "Proxy.Data.Host" );
}
if ( socks_proxy != null ){
socks_proxy = socks_proxy.trim();
}
}
});
}
public static AZInstanceManager
getSingleton(
AzureusCore core )
{
try{
class_mon.enter();
if ( singleton == null ){
singleton = new AZInstanceManagerImpl( core );
}
}finally{
class_mon.exit();
}
return( singleton );
}
private AzureusCore core;
private MCGroup mc_group;
private long search_id_next;
private List requests = new ArrayList();
private AZMyInstanceImpl my_instance;
private Map other_instances = new HashMap();
private volatile Map tcp_lan_to_ext = new HashMap();
private volatile Map udp_lan_to_ext = new HashMap();
private volatile Map udp2_lan_to_ext = new HashMap();
private volatile Map tcp_ext_to_lan = new HashMap();
private volatile Map udp_ext_to_lan = new HashMap();
private volatile Map udp2_ext_to_lan = new HashMap();
private volatile Set lan_addresses = new HashSet();
private volatile Set ext_addresses = new HashSet();
private volatile List lan_subnets = new ArrayList();
private volatile List explicit_peers = new ArrayList();
private volatile boolean include_well_known_lans = true;
private AESemaphore initial_search_sem = new AESemaphore( "AZInstanceManager:initialSearch" );
private AEMonitor this_mon = new AEMonitor( "AZInstanceManager" );
private boolean closing;
protected
AZInstanceManagerImpl(
AzureusCore _core )
{
core = _core;
my_instance = new AZMyInstanceImpl( core, this );
new AZPortClashHandler( this );
}
public void
initialize()
{
try{
mc_group =
MCGroupFactory.getSingleton(
this,
MC_GROUP_ADDRESS,
MC_GROUP_PORT,
MC_CONTROL_PORT,
null );
core.addLifecycleListener(
new AzureusCoreLifecycleAdapter()
{
public void
stopping(
AzureusCore core )
{
closing = true;
sendByeBye();
}
});
SimpleTimer.addPeriodicEvent(
"InstManager:timeouts",
ALIVE_PERIOD,
new TimerEventPerformer()
{
public void
perform(
TimerEvent event )
{
checkTimeouts();
sendAlive();
}
});
}catch( Throwable e ){
initial_search_sem.releaseForever();
Debug.printStackTrace(e);
}
new AEThread( "AZInstanceManager:initialSearch", true )
{
public void
runSupport()
{
try{
search();
// pick up our own details as soon as we can
addAddresses( my_instance );
}finally{
initial_search_sem.releaseForever();
}
}
}.start();
}
public void
trace(
String str )
{
if ( Logger.isEnabled()){
Logger.log(new LogEvent( LOGID, str ));
}
}
public void
log(
Throwable e )
{
Debug.printStackTrace(e);
}
public boolean
isInitialized()
{
return( initial_search_sem.isReleasedForever());
}
protected boolean
isClosing()
{
return( closing );
}
protected void
sendAlive()
{
sendMessage( MT_ALIVE );
}
protected void
sendAlive(
InetSocketAddress target )
{
sendMessage( MT_ALIVE, target );
}
protected void
sendByeBye()
{
sendMessage( MT_BYE );
}
protected void
sendByeBye(
InetSocketAddress target )
{
sendMessage( MT_BYE, target );
}
protected void
sendMessage(
int type )
{
sendMessage( type, (Map)null );
}
protected void
sendMessage(
int type,
InetSocketAddress target )
{
sendMessage( type, null, target );
}
protected void
sendMessage(
int type,
Map body )
{
sendMessage( type, body, null );
}
protected void
sendMessage(
int type,
Map body,
InetSocketAddress member )
{
Map map = new HashMap();
map.put( "ver", new Long(MT_VERSION));
map.put( "type", new Long(type));
Map originator = new HashMap();
map.put( "orig", originator );
my_instance.encode( originator );
if ( body != null ){
map.put( "body", body );
}
try{
if ( member == null ){
byte[] data = BEncoder.encode( map );
mc_group.sendToGroup( data );
if ( explicit_peers.size() > 0 ){
map.put( "explicit", new Long(1));
byte[] explicit_data = BEncoder.encode( map );
Iterator it = explicit_peers.iterator();
while( it.hasNext()){
mc_group.sendToMember((InetSocketAddress)it.next(), explicit_data );
}
}
}else{
if ( explicit_peers.contains( member )){
map.put( "explicit", new Long(1));
}
byte[] explicit_data = BEncoder.encode( map );
mc_group.sendToMember( member, explicit_data );
}
}catch( Throwable e ){
}
}
public void
received(
NetworkInterface network_interface,
InetAddress local_address,
InetSocketAddress originator,
byte[] data,
int length )
{
try{
Map map = BDecoder.decode(new BufferedInputStream(new ByteArrayInputStream( data, 0, length )));
long version = ((Long)map.get( "ver" )).longValue();
long type = ((Long)map.get( "type" )).longValue();
InetAddress originator_address = originator.getAddress();
if ( map.get( "explicit" ) != null ){
addInstanceSupport( originator_address, false );
}
AZOtherInstanceImpl instance = AZOtherInstanceImpl.decode( originator_address, (Map)map.get( "orig" ));
if ( type == MT_ALIVE ){
checkAdd( instance );
}else if ( type == MT_BYE ){
checkRemove( instance );
}else{
checkAdd( instance );
Map body = (Map)map.get( "body" );
if ( type == MT_REQUEST ){
String originator_id = instance.getID();
if ( !originator_id.equals( my_instance.getID())){
Map reply = requestReceived( instance, body );
if ( reply != null ){
reply.put( "oid", originator_id.getBytes());
reply.put( "rid", body.get( "rid" ));
sendMessage( MT_REPLY, reply, originator );
}
}
}else if ( type == MT_REPLY ){
String originator_id = new String((byte[])body.get( "oid" ));
if ( originator_id.equals( my_instance.getID())){
long req_id = ((Long)body.get("rid")).longValue();
try{
this_mon.enter();
for (int i=0;i<requests.size();i++){
request req = (request)requests.get(i);
if ( req.getID() == req_id ){
req.addReply( instance, body );
}
}
}finally{
this_mon.exit();
}
}
}
}
}catch( Throwable e ){
Debug.out( "Invalid packet received from " + originator, e );
}
}
protected Map
requestReceived(
AZInstance instance,
Map body )
{
// System.out.println( "received result: " + ST + "/" + AL );
long type = ((Long)body.get( "type")).longValue();
if ( type == MT_REQUEST_SEARCH ){
return( new HashMap());
}else if ( type == MT_REQUEST_TRACK ){
byte[] hash = (byte[])body.get( "hash" );
boolean seed = ((Long)body.get( "seed" )).intValue() == 1;
List dms = core.getGlobalManager().getDownloadManagers();
Iterator it = dms.iterator();
DownloadManager matching_dm = null;
try{
while( it.hasNext()){
DownloadManager dm = (DownloadManager)it.next();
TOTorrent torrent = dm.getTorrent();
if ( torrent == null ){
continue;
}
byte[] sha1_hash = (byte[])dm.getData( "AZInstanceManager::sha1_hash" );
if ( sha1_hash == null ){
sha1_hash = new SHA1Simple().calculateHash( torrent.getHash());
dm.setData( "AZInstanceManager::sha1_hash", sha1_hash );
}
if ( Arrays.equals( hash, sha1_hash )){
matching_dm = dm;
break;
}
}
}catch( Throwable e ){
Debug.printStackTrace(e);
}
if ( matching_dm == null ){
return( null );
}
int dm_state = matching_dm.getState();
if ( dm_state == DownloadManager.STATE_ERROR || dm_state == DownloadManager.STATE_STOPPED ){
return( null );
}
try{
informTracked(
new trackedInstance( instance, DownloadManagerImpl.getDownloadStatic( matching_dm ), seed ));
}catch( Throwable e ){
Debug.printStackTrace(e);
}
Map reply = new HashMap();
// XXX include DND? I don't know
reply.put( "seed", new Long( matching_dm.isDownloadComplete(true)?1:0));
return( reply );
}else{
return( null );
}
}
public void
interfaceChanged(
NetworkInterface network_interface )
{
sendAlive();
}
protected AZOtherInstanceImpl
checkAdd(
AZOtherInstanceImpl inst )
{
if ( inst.getID().equals( my_instance.getID())){
return( inst );
}
boolean added = false;
boolean changed = false;
try{
this_mon.enter();
AZOtherInstanceImpl existing = (AZOtherInstanceImpl)other_instances.get( inst.getID());
if ( existing == null ){
added = true;
other_instances.put( inst.getID(), inst );
}else{
changed = existing.update( inst );
inst = existing;
}
}finally{
this_mon.exit();
}
if ( added ){
informAdded( inst );
}else if ( changed ){
informChanged( inst );
}
return( inst );
}
protected void
checkRemove(
AZOtherInstanceImpl inst )
{
if ( inst.getID().equals( my_instance.getID())){
return;
}
boolean removed = false;
try{
this_mon.enter();
removed = other_instances.remove( inst.getID()) != null;
}finally{
this_mon.exit();
}
if ( removed ){
informRemoved( inst );
}
}
public AZInstance
getMyInstance()
{
return( my_instance );
}
protected void
search()
{
sendRequest( MT_REQUEST_SEARCH );
}
public AZInstance[]
getOtherInstances()
{
initial_search_sem.reserve();
try{
this_mon.enter();
return((AZInstance[])other_instances.values().toArray( new AZInstance[other_instances.size()]));
}finally{
this_mon.exit();
}
}
protected void
addAddresses(
AZInstance inst )
{
InetAddress internal_address = inst.getInternalAddress();
InetAddress external_address = inst.getExternalAddress();
int tcp = inst.getTCPListenPort();
int udp = inst.getUDPListenPort();
int udp2 = inst.getUDPNonDataListenPort();
modifyAddresses( internal_address, external_address, tcp, udp, udp2, true );
}
protected void
removeAddresses(
AZOtherInstanceImpl inst )
{
List internal_addresses = inst.getInternalAddresses();
InetAddress external_address = inst.getExternalAddress();
int tcp = inst.getTCPListenPort();
int udp = inst.getUDPListenPort();
int udp2 = inst.getUDPNonDataListenPort();
for (int i=0;i<internal_addresses.size();i++){
modifyAddresses( (InetAddress)internal_addresses.get(i), external_address, tcp, udp, udp2, false );
}
}
protected void
modifyAddresses(
InetAddress internal_address,
InetAddress external_address,
int tcp,
int udp,
int udp2,
boolean add )
{
if ( internal_address.isAnyLocalAddress()){
try{
internal_address = NetUtils.getLocalHost();
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
try{
this_mon.enter();
InetSocketAddress int_tcp = new InetSocketAddress(internal_address, tcp);
InetSocketAddress ext_tcp = new InetSocketAddress(external_address, tcp);
InetSocketAddress int_udp = new InetSocketAddress(internal_address, udp);
InetSocketAddress ext_udp = new InetSocketAddress(external_address, udp);
InetSocketAddress int_udp2 = new InetSocketAddress(internal_address, udp2);
InetSocketAddress ext_udp2 = new InetSocketAddress(external_address, udp2);
// not the most efficient code in the world this... will need rev
tcp_ext_to_lan = modifyAddress( tcp_ext_to_lan, ext_tcp, int_tcp, add );
tcp_lan_to_ext = modifyAddress( tcp_lan_to_ext, int_tcp, ext_tcp, add );
udp_ext_to_lan = modifyAddress( udp_ext_to_lan, ext_udp, int_udp, add );
udp_lan_to_ext = modifyAddress( udp_lan_to_ext, int_udp, ext_udp, add );
udp2_ext_to_lan = modifyAddress( udp2_ext_to_lan, ext_udp2, int_udp2, add );
udp2_lan_to_ext = modifyAddress( udp2_lan_to_ext, int_udp2, ext_udp2, add );
if ( !lan_addresses.contains( internal_address )){
Set new_lan_addresses = new HashSet( lan_addresses );
new_lan_addresses.add( internal_address );
lan_addresses = new_lan_addresses;
}
if ( !ext_addresses.contains( external_address )){
Set new_ext_addresses = new HashSet( ext_addresses );
new_ext_addresses.add( external_address );
ext_addresses = new_ext_addresses;
}
}finally{
this_mon.exit();
}
}
protected Map
modifyAddress(
Map map,
InetSocketAddress key,
InetSocketAddress value,
boolean add )
{
// System.out.println( "ModAddress: " + key + " -> " + value + " - " + (add?"add":"remove"));
InetSocketAddress old_value = (InetSocketAddress)map.get(key);
boolean same = old_value != null && old_value.equals( value );
Map new_map = map;
if ( add ){
if ( !same ){
new_map = new HashMap( map );
new_map.put( key, value );
}
}else{
if ( same ){
new_map = new HashMap( map );
new_map.remove( key );
}
}
return( new_map );
}
public InetSocketAddress
getLANAddress(
InetSocketAddress external_address,
int address_type )
{
Map map;
if ( address_type == AT_TCP ){
map = tcp_ext_to_lan;
}else if ( address_type == AT_UDP ){
map = udp_ext_to_lan;
}else{
map = udp2_ext_to_lan;
}
if ( map.size() == 0 ){
return( null );
}
return((InetSocketAddress)map.get( external_address ));
}
public InetSocketAddress
getExternalAddress(
InetSocketAddress lan_address,
int address_type )
{
Map map;
if ( address_type == AT_TCP ){
map = tcp_lan_to_ext;
}else if ( address_type == AT_UDP ){
map = udp_lan_to_ext;
}else{
map = udp2_lan_to_ext;
}
if ( map.size() == 0 ){
return( null );
}
return((InetSocketAddress)map.get( lan_address ));
}
public boolean
isLANAddress(
InetAddress address )
{
if ( DISABLE_LAN_LOCAL_STUFF ){
return( false );
}
if ( address == null ){
return( false );
}
String sp = socks_proxy;
if ( sp != null ){
if ( sp.equals( address.getHostAddress())){
return( false );
}
}
if ( include_well_known_lans ){
if ( address.isLoopbackAddress() ||
address.isLinkLocalAddress() ||
address.isSiteLocalAddress()){
return( true );
}
}
String host_address = address.getHostAddress();
for (int i=0;i<lan_subnets.size();i++){
Pattern p = (Pattern)lan_subnets.get(i);
if ( p.matcher( host_address ).matches()){
return( true );
}
}
if ( lan_addresses.contains( address )){
return( true );
}
if ( explicit_peers.size() > 0 ){
Iterator it = explicit_peers.iterator();
while( it.hasNext()){
if (((InetSocketAddress)it.next()).getAddress().equals( address )){
return( true );
}
}
}
return( false );
}
public boolean
addLANSubnet(
String subnet )
throws PatternSyntaxException
{
String str = "";
for (int i=0;i<subnet.length();i++){
char c = subnet.charAt(i);
if ( c == '*' ){
str += ".*?";
}else if ( c == '.' ){
str += "\\.";
}else{
str += c;
}
}
Pattern pattern = Pattern.compile( str );
for (int i=0;i<lan_subnets.size();i++){
if ( pattern.pattern().equals(((Pattern)lan_subnets.get(i)).pattern())){
return( false );
}
}
try{
this_mon.enter();
List new_nets = new ArrayList( lan_subnets );
new_nets.add( pattern );
lan_subnets = new_nets;
}finally{
this_mon.exit();
}
return( true );
}
public void
setIncludeWellKnownLANs(
boolean include )
{
include_well_known_lans = include;
}
public boolean
getIncludeWellKnownLANs()
{
return( include_well_known_lans );
}
public boolean
addInstance(
InetAddress explicit_address )
{
return( addInstanceSupport( explicit_address, true ));
}
protected boolean
addInstanceSupport(
InetAddress explicit_address,
boolean force_send_alive )
{
final InetSocketAddress sad = new InetSocketAddress( explicit_address, MC_GROUP_PORT );
boolean new_peer = false;
if ( !explicit_peers.contains( sad )){
try{
this_mon.enter();
List new_peers = new ArrayList( explicit_peers );
new_peers.add( sad );
explicit_peers = new_peers;
}finally{
this_mon.exit();
}
new_peer = true;
}
if ( force_send_alive || new_peer ){
// take this off the current thread as there are potential deadlock issues
// regarding this during initialisation as sending the event attempts to
// get the external address, this may hit DHT and the current thread
// maybe initialising the DHT...
new DelayedEvent(
"AZInstanceManagerImpl:delaySendAlive",
0,
new AERunnable()
{
public void
runSupport()
{
sendAlive( sad );
}
});
}
return( new_peer );
}
public boolean
isExternalAddress(
InetAddress address )
{
return( ext_addresses.contains( address ));
}
public AZInstanceTracked[]
track(
Download download )
{
if ( mc_group == null || download.getTorrent() == null || getOtherInstances().length == 0 ){
return( new AZInstanceTracked[0]);
}
Map body = new HashMap();
body.put( "hash", new SHA1Simple().calculateHash(download.getTorrent().getHash()));
body.put( "seed", new Long( download.isComplete()?1:0 ));
Map replies = sendRequest( MT_REQUEST_TRACK, body );
AZInstanceTracked[] res = new AZInstanceTracked[replies.size()];
Iterator it = replies.entrySet().iterator();
int pos = 0;
while( it.hasNext()){
Map.Entry entry = (Map.Entry)it.next();
AZInstance inst = (AZInstance)entry.getKey();
Map reply = (Map)entry.getValue();
boolean seed = ((Long)reply.get( "seed" )).intValue() == 1;
res[ pos++ ] = new trackedInstance( inst, download, seed );
}
return( res );
}
protected void
checkTimeouts()
{
long now = SystemTime.getCurrentTime();
List removed = new ArrayList();
try{
this_mon.enter();
Iterator it = other_instances.values().iterator();
while( it.hasNext()){
AZOtherInstanceImpl inst = (AZOtherInstanceImpl)it.next();
if ( now - inst.getAliveTime() > ALIVE_PERIOD * 2.5 ){
removed.add( inst );
it.remove();
}
}
}finally{
this_mon.exit();
}
for (int i=0;i<removed.size();i++){
AZOtherInstanceImpl inst = (AZOtherInstanceImpl)removed.get(i);
informRemoved( inst );
}
}
protected void
informRemoved(
AZOtherInstanceImpl inst )
{
removeAddresses( inst );
for (int i=0;i<listeners.size();i++){
try{
((AZInstanceManagerListener)listeners.get(i)).instanceLost( inst );
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
}
protected void
informAdded(
AZInstance inst )
{
addAddresses( inst );
for (int i=0;i<listeners.size();i++){
try{
((AZInstanceManagerListener)listeners.get(i)).instanceFound( inst );
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
}
protected void
informChanged(
AZInstance inst )
{
addAddresses( inst );
if ( inst == my_instance ){
sendAlive();
}
for (int i=0;i<listeners.size();i++){
try{
((AZInstanceManagerListener)listeners.get(i)).instanceChanged( inst );
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
}
protected void
informTracked(
AZInstanceTracked inst )
{
for (int i=0;i<listeners.size();i++){
try{
((AZInstanceManagerListener)listeners.get(i)).instanceTracked( inst );
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
}
protected Map
sendRequest(
int type )
{
return( new request( type, new HashMap()).getReplies());
}
protected Map
sendRequest(
int type,
Map body )
{
return( new request( type, body ).getReplies());
}
protected class
request
{
private long id;
private Set reply_instances = new HashSet();
private Map replies = new HashMap();
protected
request(
int type,
Map body )
{
try{
this_mon.enter();
id = search_id_next++;
requests.add( this );
}finally{
this_mon.exit();
}
body.put( "type", new Long( type ));
body.put( "rid", new Long( id ));
sendMessage( MT_REQUEST, body );
}
protected long
getID()
{
return( id );
}
protected void
addReply(
AZInstance instance,
Map body )
{
try{
this_mon.enter();
if ( !reply_instances.contains( instance.getID())){
reply_instances.add( instance.getID());
replies.put( instance, body );
}
}finally{
this_mon.exit();
}
}
protected Map
getReplies()
{
try{
Thread.sleep( 2500 );
}catch( Throwable e ){
}
try{
this_mon.enter();
requests.remove( this );
return( replies );
}finally{
this_mon.exit();
}
}
}
public void
addListener(
AZInstanceManagerListener l )
{
listeners.add( l );
}
public void
removeListener(
AZInstanceManagerListener l )
{
listeners.remove( l );
}
protected static class
trackedInstance
implements AZInstanceTracked
{
private AZInstance instance;
private Download download;
private boolean seed;
protected
trackedInstance(
AZInstance _instance,
Download _download,
boolean _seed )
{
instance = _instance;
download = _download;
seed = _seed;
}
public AZInstance
getInstance()
{
return( instance );
}
public Download
getDownload()
{
return( download );
}
public boolean
isSeed()
{
return( seed );
}
}
}
|