package lava.net.psyc;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import lava.net.common.UNA;
import lava.net.common.UNL;
import lava.net.common.Value;
import lava.net.common.VariableModifier;
import lava.net.common.VariableNormalizer;
import lava.net.common.ModifierParser;
import lava.net.mmp.MMPCenter;
import lava.net.mmp.MMPMessageCenter;
import lava.net.mmp.MMPException;
import lava.net.mmp.MMPDeliveryException;
import lava.net.mmp.MMPReceiverException;
import lava.net.mmp.MMPPacket;
import lava.net.mmp.MMPPacketManager;
/**
*
**/
public class PSYCMessageCenter
{
/**
*
**/
public final static String ProtocolName = "PSYC";
/**
*
**/
public final static int ProtocolMajorVersion = 0;
/**
*
**/
public final static int ProtocolMinorVersion = 7;
/**
*
**/
public final static String defaultScheme = "psyc";
/**
*
**/
public final static int defaultPort = 4404;
/**
*
**/
public final static String defaultProtocol = "tcp";
/**
*
**/
public final static String defaultResource = "/";
/**
* The maximum number of permanent variables per object/context.
* This is to prevent denial of service.
* Numbers smaller than 1 are considered infinite.
**/
public static int maxVariables = 50;
/**
*
**/
public final static char METHOD_HIERARCHY_DELIMITER = '_';
/**
*
**/
public final static char VERSION_DELIMITER = '/';
/**
*
**/
public final static char MINOR_VERSION_DELIMITER = '.';
/**
*
**/
public final static String usingProtocolsTag = //
"_using_protocols";
/**
*
**/
private final static String[] usingProtocolsAliases = //
{"using_protocols"};
/**
*
**/
public final static String understandProtocolsTag = //
"_understand_protocols";
/**
*
**/
private final static String[] understandProtocolsAliases = //
{"understand_protocols"};
/**
*
**/
public final static String usingPackagesTag = "_using_packages";
/**
*
**/
private final static String[] usingPackagesAliases = //
{"using_packages"};
/**
*
**/
public final static String understandPackagesTag = //
"_understand_packages";
/**
*
**/
private final static String[] understandPackagesAliases = //
{"understand_packages"};
/**
*
**/
public final static String contextTag = "_context";
/**
*
**/
private final static String[] contextAliases = {"context", "c"};
/**
*
**/
public final static String nameTag = "_name";
/**
*
**/
private final static String[] nameAliases = {};
/**
*
**/
public final static String identificationTag = "_identification";
/**
*
**/
private final static String[] identificationAliases = //
{"identification", "i"};
/**
*
**/
public final static String locationTag = "_location";
/**
*
**/
private final static String[] locationAliases = {};
/**
*
**/
public final static String addressesTag = "_addresses";
/**
*
**/
private final static String[] addressesAliases = {};
/**
*
**/
public final static String nameObjectTag = "_name_object";
/**
*
**/
private final static String[] nameObjectAliases = {};
/**
*
**/
public final static String descriptionTag = "_description";
/**
*
**/
private final static String[] descriptionAliases = {};
/**
*
**/
public final static String implementationTag = "_implementation";
/**
*
**/
private final static String[] implementationAliases = {};
/**
*
**/
public final static String nicknameTag = "_nick";
/**
*
**/
private final static String[] nicknameAliases = { "_nick_alias" };
/**
*
**/
public final static String contentTag = "_type_content";
/**
*
**/
private final static String[] contentAliases = {};
/**
*
**/
public final static String actionTag = "_action";
/**
*
**/
private final static String[] actionAliases = {};
/**
*
**/
public final static String pageDescriptionTag = "_page_description";
/**
*
**/
private final static String[] pageDescriptionAliases = {};
/**
*
**/
public final static String humanInformationTag = "_human_information";
/**
*
**/
private final static String[] humanInformationAliases = {};
/**
*
**/
public final static String setPrefix = "_set";
/**
*
**/
public final static String assignPrefix = "_assign";
/**
*
**/
public final static String augmentPrefix = "_augment";
/**
*
**/
public final static String diminishPrefix = "_diminish";
public class DummyManager implements PSYCPacketManager
{
/**
*
**/
public void manage(PSYCPacket packet)
{
}
/**
*
**/
public void error(PSYCException e, UNL remote)
{
}
/**
*
**/
public void reset(UNL remote)
{
}
}
/**
* Hash to find out if we know the variable name
**/
private Hashtable knownVars = new Hashtable();
/**
*
**/
private PSYCPacketManager manager = null;
/**
*
**/
private MMPCenter mmpCenter = null;
/**
*
**/
private Normalizer normalizer = new Normalizer();
/**
*
**/
private MMPPacketManager peer = new PacketManager();
/**
* mapping UNA -> UNL without context
**/
private Hashtable objects = new Hashtable();
/**
* mapping UNL without context -> Vector of UNA
**/
private Hashtable addresses = new Hashtable();
/**
* mapping UNL without context -> Hashtable of ASSIGNed contexts
**/
private Hashtable incomingContexts = new Hashtable();
/**
* mapping UNL -> Hashtable of global variables
**/
private Hashtable globVars = new Hashtable();
/**
* mapping UNL -> Hashtable of temporarily variables
**/
private Hashtable tempVars = new Hashtable();
/**
* mapping UNL -> Vector of outgoing variables
**/
private Hashtable outgoings = new Hashtable();
/**
* mapping context name -> Hashtable of context variables
**/
private Hashtable outgoingContexts = new Hashtable();
/**
* mapping context name -> Hashtable of peers (UNL without context, UNL)
**/
private Hashtable outgoingContextInvolved = new Hashtable();
///**
// * mark locations as dead
// **/
//private Hashtable deadLocations = new Hashtable();
/**
* mapping variable alias -> normalized variable
**/
private Hashtable variableAlias = new Hashtable();
/**
* mapping method alias -> normalized method
**/
private Hashtable methodAlias = new Hashtable();
/**
*
**/
private PSYCDeliveryException gotException = null;
/**
* for packages
**/
private Hashtable packages = new Hashtable();
/**
*
**/
private Hashtable callPackagesVariable = new Hashtable();
/**
*
**/
private Hashtable callPackagesMethod = new Hashtable();
/**
*
**/
private Hashtable callPackagesError = new Hashtable();
/**
*
**/
private Hashtable method = new Hashtable();
/**
* For greeting... a list of protocols this message center understands.
**/
public Value understandProtocols = null;
/**
*
**/
private Value usingPackages = null;
/**
*
**/
private Value understandPackages = null;
/**
* For greeting... a message method which is sent to new connected
* remote objects.
**/
private String greetingMethod = null;
/**
* For greeting... the body of the message which is sent to new connected
* remote objects.
**/
private String greetingBody = null;
/**
* This creates a new instance of a message center for the PSYC
* protocol.
* This instance does not listen at the network and therefor it
* cannot be reached from the outside except it establishes
* connections itself (for example by sending messages to some
* remote object - then it can be reached by this object).
**/
public PSYCMessageCenter()
{
this (null);
}
/**
* This creates a new instance of a message center for the PSYC
* protocol that sends every information it gets to the specified
* packet manager.
* If the manager is null, it will be ignored.
* This instance does not listen at the network and therefor it
* cannot be reached from the outside except it establishes
* connections itself (for example by sending messages to some
* remote object - then it can be reached by this object).
**/
public PSYCMessageCenter(PSYCPacketManager manager)
{
this (manager,(MMPCenter)null);
}
/**
* This creates a new instance of a message center for the PSYC
* protocol that sends every information it gets to the specified
* packet manager.
* If the manager is null, it will be ignored.
* The flag listen specifies, if the message center is listening
* at the network for incoming messages.
* If it should listen, it tries listenig at the PSYC well known
* port, if this is not possible, it will listen at random ports.
**/
public PSYCMessageCenter(PSYCPacketManager manager, boolean listen)
{
setDefaults();
setManager(manager);
setMMPCenter(new MMPMessageCenter(peer,listen));
initializeAliases();
}
/**
* This creates a new instance of a message center for the PSYC
* protocol that sends every information it gets to the specified
* packet manager.
* If the manager is null, it will be ignored.
* The array listenLocations specifies a set of locations, the
* center should listen on.
* If it cannot listen at some of the locations, they'll be ignored.
**/
public PSYCMessageCenter(PSYCPacketManager manager, UNA[] listenLocations)
{
setDefaults();
setManager(manager);
setMMPCenter(new MMPMessageCenter(peer,listenLocations));
initializeAliases();
}
/**
* This creates a new instance of a message center for the PSYC
* protocol that sends every information it gets to the specified
* packet manager and the specified underlying transport manager.
* If the manager is null, it will be ignored.
* If the transport manager is null, a default one will be created.
**/
public PSYCMessageCenter(PSYCPacketManager manager, //
MMPCenter center)
{
setDefaults();
setManager(manager);
setMMPCenter(center == null ? new MMPMessageCenter(peer) : center);
initializeAliases();
}
/**
* Sets the default values for UNA/UNL/UNI.
* This is called by the PSYCMessageCenter constructors normally.
* It does also call the setDefaults of the MMPMessageCenter.
* If it is called manually, this must be done before some
* UNA/UNL/UNI is instantiated.
**/
public static void setDefaults()
{
UNL.setDefaults(defaultScheme,MMPMessageCenter.getLocalHost(),//
defaultPort,defaultProtocol,defaultResource);
MMPMessageCenter.setDefaults();
}
/**
* Sets the underlying MMPCenter which is called by this
* PSYCMessageCenter.
**/
public void setMMPCenter(MMPCenter mmpCenter)
{
if(mmpCenter == null)
return;
this.mmpCenter = mmpCenter;
}
/**
* Returns the underlying MMPCenter which is called by this
* PSYCMessageCenter.
**/
public MMPCenter getMMPCenter()
{
return mmpCenter;
}
/**
* Sets the PSYCPacketManager which is called by this
* PSYCMessageCenter if it delivers some PSYC event.
*
* @see lava.net.psyc.PSYCMessageCenter#addPackage(lava.net.psyc.PSYCPackage)
**/
public PSYCPacketManager setManager(PSYCPacketManager manager)
{
if(manager == null)
manager = new DummyManager();
PSYCPacketManager old = this.manager;
this.manager = manager;
return old;
}
/**
* Closes this message center.
**/
public synchronized void close()
{
mmpCenter.close();
}
/**
* For greeting ... the method and the body which is sent to new connected
* remote objects. This is not required by the PSYC protocol, so it can
* be defined as liked.
**/
public void setGreeting(String method, String body)
{
greetingMethod = method;
greetingBody = body;
}
/**
* Adds a package to this message center.
*
* @see lava.net.psyc.PSYCMessageCenter#setManager(lava.net.psyc.PSYCPacketManager)
**/
public boolean addPackage(PSYCPackage pack)
{
if(pack == null)
return false;
if(packages.get(pack.getClass()) != null)
return false;
packages.put(pack.getClass(),pack);
String name = pack.getPackageName();
if(name != null && name.length() > 0)
{
//Vector vars = new Vector();
if(pack.uses())
if(usingPackages == null)
{
usingPackages = new Value(name);
assignVariable((UNL)null,usingPackagesTag,usingPackages,//
true);
}
else
{
usingPackages.augment(name);
augmentVariable((UNL)null,usingPackagesTag,new Value(name),//
true);
}
if(pack.understands())
if(understandPackages == null)
{
understandPackages = new Value(name);
assignVariable((UNL)null,understandPackagesTag,//
understandPackages,true);
}
else
{
understandPackages.augment(name);
augmentVariable((UNL)null,understandPackagesTag,//
new Value(name),true);
}
}
if(pack.wantsErrors())
callPackagesError.put(pack,pack);
String[] variables = pack.getVariables();
if(variables != null && variables.length > 0)
for(int i = 0;i < variables.length;++i)
{
Hashtable packages = //
(Hashtable)callPackagesVariable.get(variables[i]);
if(packages == null)
callPackagesVariable.put(variables[i],//
packages = new Hashtable());
packages.put(pack,pack);
}
String[] methods = pack.getMethods();
if(methods != null && methods.length > 0)
for(int i = 0;i < methods.length;++i)
{
Hashtable packages = //
(Hashtable)callPackagesMethod.get(methods[i]);
if(packages == null)
callPackagesMethod.put(methods[i],packages = new Hashtable());
packages.put(pack,pack);
}
pack.registerCenter(this);
return true;
}
/**
* Guess addresses of the given object and initialize the object-address
* mapping with them.
**/
private void initMapping(UNL object)
{
String scheme = object.getScheme();
String host = object.getHostName();
int port = object.getPort();
String protocol = object.getProtocol();
String resource = object.getResource();
Vector addresses = new Vector();
UNA address;
for(int i = 0;i < MMPMessageCenter.protocols.length;++i)
{
address = new UNA(scheme,host,port,//
MMPMessageCenter.protocols[i],resource);
if(address.getProtocol().equals(object.getProtocol()))
addresses.insertElementAt(address,0);
else
addresses.addElement(address);
}
initMapping(object,addresses);
}
/**
* Initialize the object-address mapping.
**/
private void initMapping(UNL object, Vector addresses)
{
boolean hasDefault = false;
int i;
// for now, remove every other stuff if we have tcp
for(i = 0;!hasDefault && i < addresses.size();++i)
if(((UNA)addresses.elementAt(i)).getProtocol().equals(//
MMPMessageCenter.defaultProtocol))
hasDefault = true;
if(hasDefault)
for(i = 0;i < addresses.size();++i)
if(!((UNA)addresses.elementAt(i)).getProtocol().equals(//
MMPMessageCenter.defaultProtocol))
addresses.removeElementAt(i--);
this.addresses.put(object,addresses);
for(Enumeration e = addresses.elements();e.hasMoreElements();)
objects.put(e.nextElement(),object);
}
/**
* Remove the specified address from its objects address mapping.
**/
private void removeAddress(UNA address)
{
if(address == null)
return;
UNL object = (UNL)objects.get(address);
if(object == null)
return;
Vector addresses = (Vector)this.addresses.get(object.withoutContext());
if(addresses == null)
return;
for(int i = 0;i < addresses.size();++i)
if(addresses.elementAt(i).equals(address))
addresses.removeElementAt(i--);
this.addresses.remove(address);
}
/**
* Remove the object-address mapping for the specified object.
**/
private void removeObject(UNL object)
{
if(object == null)
return;
Vector addresses = (Vector)this.addresses.remove(//
object.withoutContext());
if(addresses == null)
return;
for(Enumeration e = addresses.elements();e.hasMoreElements();)
objects.remove(e.nextElement());
}
/**
* Returns the actual address for a given object.
**/
public UNA getAddress(UNL object)
{
if(object == null)
return null;
Vector addresses = (Vector)this.addresses.get(object.withoutContext());
if(addresses == null)
{
initMapping(object.withoutContext());
addresses = (Vector)this.addresses.get(object.withoutContext());
}
UNA address = addresses.size() > 0 ? //
(UNA)addresses.firstElement() : null;
return address;
}
/**
* Returns the object for a given address.
**/
public UNL getObject(UNA address)
{
if(address == null)
return null;
UNL object = (UNL)objects.get(address);
if(object == null)
{
Vector addresses = new Vector();
addresses.addElement(address);
initMapping(new UNL(address),addresses);
object = (UNL)objects.get(address);
}
return object;
}
/**
* Adds a variable alias to the message centers variable expand buffer.
**/
public void addVariableAlias(String alias, String longVar)
{
if(alias == null || longVar == null)
return;
variableAlias.put(alias,longVar);
}
/**
* Removes a variable alias from the message centers variable expand buffer.
**/
public String removeVariableAlias(String alias)
{
if(alias == null)
return null;
return (String)variableAlias.remove(alias);
}
/**
* Adds a method alias to the message centers method expand buffer.
**/
public void addMethodAlias(String alias, String longName)
{
if(alias == null || longName == null)
return;
methodAlias.put(alias,longName);
}
/**
* Removes a method alias from the message centers method expand buffer.
**/
public String removeMethodAlias(String alias)
{
if(alias == null)
return null;
return (String)methodAlias.remove(alias);
}
private class Normalizer implements VariableNormalizer
{
/**
*
**/
public String normalizeVariableName(String name)
{
if(name == null)
return null;
String expanded = (String)variableAlias.get(name);
if(expanded == null)
return name;
return expanded;
}
/**
*
**/
public String normalizeMethodName(String name)
{
if(name == null)
return null;
String expanded = (String)methodAlias.get(name);
if(expanded == null)
return name;
return expanded;
}
}
/**
*
**/
private void initializeAliases()
{
Value v = new Value();
int i;
for(i = 0;i < usingProtocolsAliases.length;++i)
addVariableAlias(usingProtocolsAliases[i],usingProtocolsTag);
for(i = 0;i < understandProtocolsAliases.length;++i)
addVariableAlias(understandProtocolsAliases[i],//
understandProtocolsTag);
for(i = 0;i < usingPackagesAliases.length;++i)
addVariableAlias(usingPackagesAliases[i],usingPackagesTag);
for(i = 0;i < understandPackagesAliases.length;++i)
addVariableAlias(understandPackagesAliases[i],//
understandPackagesTag);
for(i = 0;i < contextAliases.length;++i)
addVariableAlias(contextAliases[i],contextTag);
for(i = 0;i < nameAliases.length;++i)
addVariableAlias(nameAliases[i],nameTag);
for(i = 0;i < identificationAliases.length;++i)
addVariableAlias(identificationAliases[i],identificationTag);
for(i = 0;i < locationAliases.length;++i)
addVariableAlias(locationAliases[i],locationTag);
for(i = 0;i < addressesAliases.length;++i)
addVariableAlias(addressesAliases[i],addressesTag);
for(i = 0;i < nameObjectAliases.length;++i)
addVariableAlias(nameObjectAliases[i],nameObjectTag);
for(i = 0;i < descriptionAliases.length;++i)
addVariableAlias(descriptionAliases[i],descriptionTag);
for(i = 0;i < implementationAliases.length;++i)
addVariableAlias(implementationAliases[i],implementationTag);
for(i = 0;i < nicknameAliases.length;++i)
addVariableAlias(nicknameAliases[i],nicknameTag);
for(i = 0;i < contentAliases.length;++i)
addVariableAlias(contentAliases[i],contentTag);
for(i = 0;i < actionAliases.length;++i)
addVariableAlias(actionAliases[i],actionTag);
for(i = 0;i < pageDescriptionAliases.length;++i)
addVariableAlias(pageDescriptionAliases[i],pageDescriptionTag);
for(i = 0;i < humanInformationAliases.length;++i)
addVariableAlias(humanInformationAliases[i],//
humanInformationTag);
Value prot = new Value(ProtocolName + "/" + //
ProtocolMajorVersion + "." + ProtocolMinorVersion);
Value sub = mmpCenter.usingProtocols();
if(sub != null)
{
String s = sub.toString();
if(s != null && s.length() > 0)
prot.augment(s);
}
assignVariable((UNL)null,usingProtocolsTag,prot,false);
UNA[] addresses = mmpCenter.getListenLocations();
if(addresses != null && addresses.length > 0)
{
Value addr = new Value();
String name_object = null;
int bestMatch = Integer.MAX_VALUE;
for(i = 0;i < addresses.length;++i)
{
String addresses_ = addresses[i].toString();
addr.augment(addresses_);
int actual = addresses_.length();
if(actual < bestMatch || name_object == null)
{
bestMatch = actual;
name_object = addresses_;
}
}
addr.diminish(name_object);
Value addrs = new Value(name_object);
addrs.augment(addr.toString());
assignVariable((UNL)null,addressesTag,addrs,false);
assignVariable((UNL)null,nameObjectTag,new Value(name_object),//
false);
}
Value implementation = new Value();
implementation.augment(ProtocolName + VERSION_DELIMITER + //
ProtocolMajorVersion + MINOR_VERSION_DELIMITER + //
ProtocolMinorVersion);
String runtime = "java";
String os_name = "Applet";
String os_arch = "Unknown";
if(!UNL.isApplet())
{
os_name = "Application";
String tmp = System.getProperty("java.version");
if(tmp != null)
runtime = runtime + VERSION_DELIMITER + tmp;
tmp = System.getProperty("os.name");
if(tmp != null)
os_name = tmp;
tmp = System.getProperty("os.version");
if(tmp != null)
os_name = os_name + VERSION_DELIMITER + tmp;
tmp = System.getProperty("os.arch");
if(tmp != null)
os_arch = tmp;
}
implementation.augment(runtime);
implementation.augment(os_name);
implementation.augment(os_arch);
assignVariable((UNL)null,implementationTag,implementation,false);
}
/**
* Returns a list of the names of all variables currently set
* by the specified remote object.
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public String[] getVars(UNL remote)
{
String[] names;
if(remote == null)
{
synchronized(knownVars)
{
int size = knownVars.size();
int i = 0;
names = new String[size];
for(Enumeration e = knownVars.keys();e.hasMoreElements();)
names[i++] = (String)e.nextElement();
}
}
else
{
Hashtable globVars = (Hashtable)this.globVars.get(remote);
Hashtable tempVars = (Hashtable)this.tempVars.get(remote);
int size, i = 0;
Enumeration e;
synchronized(globVars)
{
synchronized(tempVars)
{
if(globVars != null)
{
size = globVars.size();
if(tempVars != null)
for(e = tempVars.keys();e.hasMoreElements();)
if(globVars.get(e.nextElement()) == null)
++size;
}
else
size = tempVars == null ? 0 : tempVars.size();
names = new String[size];
String tmp;
if(globVars != null)
for(e = globVars.keys();e.hasMoreElements();)
names[i++] = (String)e.nextElement();
if(tempVars != null)
for(e = tempVars.keys();e.hasMoreElements();)
{
tmp = (String)e.nextElement();
if(globVars == null || globVars.get(tmp) == null)
names[i++] = tmp;
}
}
}
}
return names;
}
/**
* Returns the Value currently set for the specified variable
* by the specified remote object.
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public Value getValue(UNL remote, String name)
{
if(name == null)
return null;
Value val;
Hashtable vars = knownVars;
if(remote != null)
{
vars = (Hashtable)tempVars.get(remote);
if(vars == null)
vars = (Hashtable)globVars.get(remote);
else
if((val = (Value)vars.get(name)) != null)
return val;
else
vars = (Hashtable)globVars.get(remote);
if(vars != null && (val = (Value)vars.get(name)) != null)
return val;
if(remote.getContext() != null)
return getValue(remote.withoutContext(),name);
else
return null;
}
return (Value)vars.get(name);
}
/**
* Removes the specified variable currently set by the specified remote
* object. Returns the removed value.
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public Value removeVariable(UNL remote, String name)
{
if(name == null)
return null;
Value old = getValue(remote,name);
if(remote != null)
{
Hashtable vars = (Hashtable)tempVars.get(remote);
if(vars != null)
vars.remove(name);
else
{
vars = (Hashtable)globVars.get(remote);
if(vars != null)
vars.remove(name);
}
}
else
knownVars.remove(name);
return old;
}
/**
* Checks the specified (list-)variable of the specified remote object, if
* it contains the specified element.
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
private boolean checkElement(UNL remote, String name, String element)
{
if(element == null || element.length() <= 0)
return false;
Value v = getValue(remote,name);
if(v == null)
return true;
String value = v.toString();
int index = value.indexOf(element);
if(index < 0)
return false;
if(index > 0)
{
char prev = value.charAt(index - 1);
boolean found = false;
for(int i = 0;i < Value.listSeparator.length;++i)
if(prev == Value.listSeparator[i])
{
found = true;
break;
}
if(!found)
return false;
}
int nextpos = element.length() + index;
if(nextpos >= value.length())
return true;
char next = value.charAt(nextpos);
if(next == VERSION_DELIMITER)
return true;
for(int i = 0;i < Value.listSeparator.length;++i)
if(next == Value.listSeparator[i])
return true;
return false;
}
/**
* Returns a list of protocols currently used by the specified remote
* object.
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public String[] getUsingProtocols(UNL remote)
{
Value v = getValue(remote,usingProtocolsTag);
if(v != null)
return v.toList();
return null;
}
/**
* Checks, if the specified remote object uses the specified protocol.
**/
public boolean usesProtocol(UNL remote, String name)
{
return checkElement(remote,usingProtocolsTag,name);
}
/**
* Returns a list of protocols the specified remote object understands.
**/
public String[] getUnderstandProtocols(UNL remote)
{
Value v = getValue(remote,understandProtocolsTag);
if(v != null)
return v.toList();
return null;
}
/**
* Checks, if the specified remote object understands the specified
* protocol.
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public boolean understandsProtocol(UNL remote, String name)
{
return checkElement(remote,understandProtocolsTag,name);
}
/**
*
**/
public void assignUnderstandProtocol(UNL remote, String protocol)
{
assignVariable(remote,understandProtocolsTag,new Value(protocol),//
true);
}
/**
*
**/
public void augmentUnderstandProtocol(UNL remote, String protocol)
{
augmentVariable(remote,understandProtocolsTag,new Value(protocol),//
true);
}
/**
*
**/
public void diminishUnderstandProtocol(UNL remote, String protocol)
{
diminishVariable(remote,understandProtocolsTag,new Value(protocol),//
true);
}
/**
* Returns a list of packages currently used by the specified remote
* object.
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public String[] getUsingPackages(UNL remote)
{
Value v = getValue(remote,usingPackagesTag);
if(v != null)
return v.toList();
return null;
}
/**
* Checks, if the specified remote object uses the specified
* package.
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public boolean usesPackage(UNL remote, String name)
{
return checkElement(remote,usingPackagesTag,name);
}
/**
* Returns a list of packages the specified remote object understands.
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public String[] getUnderstandPackages(UNL remote)
{
Value v = getValue(remote,understandPackagesTag);
if(v != null)
return v.toList();
return null;
}
/**
* Checks, if the specified remote object understands the specified
* package.
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public boolean understandsPackage(UNL remote, String name)
{
return checkElement(remote,understandPackagesTag,name);
}
/**
* Returns the full name of the specified remote object.
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public String getName(UNL remote)
{
Value v = getValue(remote,nameTag);
if(v != null)
return v.toString();
return null;
}
/**
*
**/
public void setName(UNL remote, String name)
{
if(name != null)
assignVariable(remote,nameTag,new Value(name),true);
else
diminishVariable(remote,nameTag,null,true);
}
/**
* Returns the Uniform Network Identification
* of the specified remote object.
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public UNI getIdentification(UNL remote)
{
Value v = getValue(remote,identificationTag);
if(v != null)
return new UNI(v.toString());
return null;
}
/**
*
**/
public void setIdentification(UNL remote, UNI identification)
{
if(identification != null)
assignVariable(remote,identificationTag,//
new Value(identification.toString()),true);
else
diminishVariable(remote,identificationTag,null,true);
}
/**
* Returns a list of all Uniform Network Locations
* of the specified remote object.
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public UNL[] getLocations(UNL remote)
{
Value v = getValue(remote,locationTag);
if(v != null)
{
String[] list = v.toList();
UNL[] locations = new UNL[list.length];
for(int i = 0;i < list.length;++i)
locations[i] = new UNL(list[i]);
return locations;
}
return null;
}
/**
*
**/
public void assignLocation(UNL remote, UNL location)
{
if(location != null)
assignVariable(remote,locationTag,new Value(location.toString()),//
true);
}
/**
*
**/
public void augmentLocation(UNL remote, UNL location)
{
if(location != null)
augmentVariable(remote,locationTag,new Value(location.toString()),//
true);
}
/**
*
**/
public void diminishLocation(UNL remote, UNL location)
{
diminishVariable(remote,locationTag,//
location == null ? null : new Value(location.toString()),//
true);
}
/**
*
**/
public UNL getObjectName(UNL remote)
{
Value v = getValue(remote,nameObjectTag);
if(v != null)
return new UNL(v.toString());
return null;
}
/**
* Returns a Virtual Environment Description Language (VEDL)
* object description of the specified remote object.
* VEDL object descriptions are not supported yet.
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public Object getDescription(UNL remote)
{
return getValue(remote,descriptionTag);
}
/**
*
**/
public void setDescription(UNL remote, Object description)
{
if(description != null)
assignVariable(remote,descriptionTag,//
new Value(description.toString()),true);
else
diminishVariable(remote,descriptionTag,null,true);
}
/**
* Returns a list of platforms the specified remote object is
* implemented on.
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public String[] getImplementation(UNL remote)
{
Value v = getValue(remote,implementationTag);
if(v != null)
return v.toList();
return null;
}
/**
* Returns the Nickname of the specified remote object
* (Conferencing specific stuff).
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public String getNickname(UNL remote)
{
Value v = getValue(remote,nicknameTag);
if(v != null)
return v.toString();
return null;
}
/**
*
**/
public void setNickname(UNL remote, String nickname)
{
if(nickname != null)
assignVariable(remote,nicknameTag,new Value(nickname),true);
else
diminishVariable(remote,nicknameTag,null,true);
}
/**
* Returns the actual content type, the specified remote object
* is using for its bodies.
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public String getContentType(UNL remote)
{
Value v = getValue(remote,contentTag);
if(v != null)
return v.toString();
return null;
}
/**
*
**/
public void setContentType(UNL remote, String contentType)
{
if(contentType != null)
assignVariable(remote,contentTag,new Value(contentType),true);
else
diminishVariable(remote,contentTag,null,true);
}
/**
* Returns a currently set action of the specified remote object
* (Conferencing specific stuff).
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public String getAction(UNL remote)
{
Value v = getValue(remote,actionTag);
if(v != null)
return v.toString();
return null;
}
/**
*
**/
public void setAction(UNL remote, String action)
{
if(action != null)
assignVariable(remote,actionTag,new Value(action),true);
else
diminishVariable(remote,actionTag,null,true);
}
/**
* Returns the URL where the specified remote object is described on
* (Conferencing specific stuff - for example a home page).
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public URL getURLDescription(UNL remote)
{
Value v = getValue(remote,pageDescriptionTag);
if(v != null)
try
{
return new URL(v.toString());
}
catch(MalformedURLException e)
{
}
return null;
}
/**
*
**/
public void setURLDescription(UNL remote, URL description)
{
if(description != null)
assignVariable(remote,pageDescriptionTag,//
new Value(description.toString()),true);
else
diminishVariable(remote,pageDescriptionTag,null,true);
}
/**
* Returns a human readable description of the specified remote object.
* If remote is null, it returns the same for itself.
* This means the Value which is sent to every new connected remote.
**/
public String getHumanInformation(UNL remote)
{
Value v = getValue(remote,humanInformationTag);
if(v != null)
return v.toString();
return null;
}
/**
*
**/
public void setHumanInformation(UNL remote, String information)
{
if(information != null)
assignVariable(remote,humanInformationTag,new Value(information),//
true);
else
diminishVariable(remote,humanInformationTag,null,true);
}
/**
* Returns the actual method the specified remote object has sent.
* Only defined while PSYCPackage.received() is called.
* If remote is null, it returns null at all.
**/
public String getActualMethod(UNL remote)
{
if(remote == null)
return null;
return (String)method.get(remote);
}
/**
*
**/
public MMPPacketManager getMMPPacketManager()
{
return peer;
}
private class PacketManager implements MMPPacketManager
{
/**
*
**/
public String getGreetingBody(UNA remote, UNA local)
{
Vector greetingVars = new Vector();
for(Enumeration e = knownVars.keys();e.hasMoreElements();)
{
String name = (String)e.nextElement();
greetingVars.addElement(new VariableModifier(//
VariableModifier.GLYPH_ASSIGN,name,//
(Value)knownVars.get(name)));
}
return preparePacket(greetingMethod,greetingBody,//
null,greetingVars);
}
/**
*
**/
public void error(MMPException e, UNA remote, UNA local, //
MMPPacket packet)
{
if(e == null)
return;
int code = e.getErrorCode();
boolean cleanObject = false;
try
{
if(e instanceof MMPReceiverException)
{
if(code == MMPReceiverException.CLOSED && remote != null)
{
UNL r = getObject(remote);
removeAddress(remote);
if(getAddress(r) != null)
{
// everything's fine, we can still communicate
// with the object
// send a null message for testing
try
{
send(r,null,null,null);
}
catch(PSYCDeliveryException ex)
{
}
return;
}
// whoups, we cannot communicate any more with the object
cleanObject = true;
}
// for now, ignore every exception in case of received packets
// TODO: make that better
}
else
{
UNL r = getObject(remote);
// save the error for method calls
gotException = new PSYCDeliveryException(//
(MMPDeliveryException)e);
// for now, ignore every unspecified error
if(code == MMPDeliveryException.NO_ERROR_CODE_GIVEN)
return;
removeAddress(remote);
UNA nextTry = getAddress(r);
// check next address for that UNL
if(nextTry != null)
mmpCenter.send(nextTry,packet);
else
{
// if there are no more UNAs, call packet manager
manager.error(gotException,r);
cleanObject = true;
}
}
}
finally
{
if(cleanObject)
{
UNL r = getObject(remote);
for(Enumeration en = callPackagesError.keys();//
en.hasMoreElements();)
((PSYCPackage)en.nextElement()).reset(r);
manager.reset(r);
// step through all contexts and remove if its involved
for(Enumeration en = outgoingContextInvolved.elements();//
en.hasMoreElements();)
((Hashtable)en.nextElement()).remove(r);
globVars.remove(r);
tempVars.remove(r);
removeObject(r);
}
}
}
/**
*
**/
public void manage(MMPPacket packet)
{
String mmpBody = packet.getStringBody();
int mmpBodyLength = mmpBody == null ? 0 : mmpBody.length();
int i = 0;
boolean gotEOL = true;
String variables = null;
String method = null;
String body = null;
char ch;
// get variables, method and body
try
{
while(i < mmpBodyLength)
{
ch = mmpBody.charAt(i);
if(gotEOL && !VariableModifier.isGlyph(ch) && //
ch != VariableModifier.VALUE_SEPARATOR)
break;
gotEOL = ch == VariableModifier.EOL;
++i;
}
variables = mmpBody.substring(0,i);
int beginMethod = i;
while(i < mmpBodyLength)
{
ch = mmpBody.charAt(i);
if(ch == ' ' || ch == VariableModifier.VALUE_SEPARATOR || //
ch == VariableModifier.EOL)
break;
++i;
}
method = normalizer.normalizeMethodName(//
mmpBody.substring(beginMethod,i));
body = mmpBody.substring(i + 1);
}
catch(StringIndexOutOfBoundsException e)
{
}
;
if(variables != null && variables.length() <= 0)
variables = null;
if(method != null && method.length() <= 0)
method = null;
if(body != null && body.length() <= 0)
body = null;
UNA remote = packet.getRemote();
if(remote == null)
return;
Vector header = ModifierParser.parseHeader(normalizer,variables);
VariableModifier modifier;
char glyph;
String name;
Value value;
boolean removeContext = false;
boolean staticContext = false;
String context = null;
Value addresses = null;
UNL source = (UNL)objects.get(remote);
// first step: run through the variables and get them we need for us
if(header != null)
for(i = 0;i < header.size();++i)
{
modifier = (VariableModifier)header.elementAt(i);
name = modifier.getName();
if(contextTag.equals(name))
{
glyph = modifier.getGlyph();
value = modifier.getValue();
if(value == null || value.toString().length() <= 0)
{
if(glyph == VariableModifier.GLYPH_DIMINISH)
{
// handle remove on complete variable explicitely
removeContext = true;
context = null;
}
}
else
if(glyph == VariableModifier.GLYPH_SET || //
glyph == VariableModifier.GLYPH_ASSIGN)
{
context = value.toString();
if(VariableModifier.isTemporary(glyph))
staticContext = false;
else
staticContext = true;
}
//header.removeElementAt(i--);
continue;
}
if(addressesTag.equals(name))
{
if(addresses == null)
{
// address change - load all addresses without possible
// initialization of the object name
addresses = new Value();
if(source != null)
{
// ah, we know this object already
Vector addrs = (Vector)PSYCMessageCenter.this.addresses.remove(//
source.withoutContext());
if(addrs != null)
for(Enumeration e = addrs.elements();//
e.hasMoreElements();)
{
UNA addr = (UNA)e.nextElement();
PSYCMessageCenter.this.objects.remove(addr);
addresses.augment(addr.toString());
}
}
}
glyph = modifier.getGlyph();
value = modifier.getValue();
if(glyph == VariableModifier.GLYPH_DIMINISH)
{
if(value == null || value.toString().length() <= 0)
{
// handle remove on complete variable explicitely
addresses = new Value();
}
else
{
// we diminish one or more addresses
addresses.diminish(value);
}
}
else
if(glyph == VariableModifier.GLYPH_ASSIGN)
{
addresses = value;
}
else
if(glyph == VariableModifier.GLYPH_AUGMENT)
{
addresses.augment(value.toString());
}
// ignore temporarily set addresses
//header.removeElementAt(i--);
continue;
}
}
if(addresses != null)
{
// we got an addresses tag
String[] list = addresses.toList();
Vector addrs = new Vector();
if(list.length > 0)
{
if(source == null)
source = new UNL(list[0]);
for(i = 0;i < list.length;++i)
addrs.addElement(new UNA(list[i]));
}
// (re)initialize the mapping
addrs.insertElementAt(remote,0);
if(source == null)
source = new UNL(remote);
initMapping(source,addrs);
}
source = getObject(remote);
if(removeContext)
incomingContexts.remove(source);
if(context == null)
context = (String)incomingContexts.get(source);
else
if(staticContext)
incomingContexts.put(source,context);
if(context != null)
source = source.addContext(context);
Hashtable packages;
Hashtable globVars = //
(Hashtable)PSYCMessageCenter.this.globVars.get(source);
Hashtable tempVars = //
(Hashtable)PSYCMessageCenter.this.tempVars.get(source);
if(globVars == null)
PSYCMessageCenter.this.globVars.put(//
source,globVars = new Hashtable());
if(tempVars == null)
PSYCMessageCenter.this.tempVars.put(//
source,tempVars = new Hashtable());
synchronized(globVars)
{
synchronized(tempVars)
{
tempVars.clear();
if(header != null && header.size() > 0)
{
for(Enumeration e = header.elements();//
e.hasMoreElements();)
{
modifier = (VariableModifier)e.nextElement();
glyph = modifier.getGlyph();
name = modifier.getName();
value = modifier.getValue();
do
{
if(value == null || value.toString().length() <= 0)
if(glyph == VariableModifier.GLYPH_DIMINISH)
{
// handle remove on complete variable explicitely
tempVars.remove(name);
globVars.remove(name);
continue;
}
else
if(value == null)
value = new Value();
if(glyph == VariableModifier.GLYPH_SET)
tempVars.put(name,value);
else
if(glyph == VariableModifier.GLYPH_ASSIGN)
{
if(globVars.size() < maxVariables || //
maxVariables < 1)
{
globVars.put(name,value);
}
else
{
//TODO: generate some error
}
}
else
if(glyph == VariableModifier.GLYPH_AUGMENT || //
glyph == VariableModifier.GLYPH_DIMINISH)
{
Value oldVal = getValue(source,name);
if(oldVal == null)
{
if(globVars.size() < maxVariables || //
maxVariables < 1)
{
globVars.put(name,oldVal = new Value());
}
else
{
//TODO: generate some error
}
}
oldVal.handle(glyph,value.toString());
}
else
if(glyph == VariableModifier.GLYPH_QUERY)
{
Value ourValue = getValue(null,name);
if(ourValue != null)
assignVariable(source,name,ourValue,true);
}
}
while(false);
if((packages = //
(Hashtable)callPackagesVariable.get(name)) != null)
for(Enumeration ee = packages.keys();//
ee.hasMoreElements();)
((PSYCPackage)ee.nextElement()).//
variableChanged(source,modifier);
}
}
PSYCPacket p = new PSYCPacket(source,header,method,body);
if(p.isEmpty())
return;
// call packages
if(method != null)
{
PSYCMessageCenter.this.method.put(source,method);
for(Enumeration e = callPackagesMethod.keys();//
e.hasMoreElements();)
{
name = (String)e.nextElement();
// check if method is equal or submethod
// of the registered method
if(method.regionMatches(0,name,0,name.length()) && (//
method.length() == name.length() || //
method.charAt(name.length()) == //
METHOD_HIERARCHY_DELIMITER))
{
packages = (Hashtable)callPackagesMethod.get(name);
for(Enumeration ee = packages.keys();//
ee.hasMoreElements();)
// send them the registered method name not the real
((PSYCPackage)ee.nextElement()).received(source,//
name,body);
}
}
PSYCMessageCenter.this.method.remove(source);
}
// call packet manager
manager.manage(p);
}
}
}
}
/**
* Creates the specified outgoing context.
**/
public void createContext(String context)
{
if(context == null)
return;
if(!isContext(context))
{
outgoingContexts.put(context,new Hashtable());
outgoingContextInvolved.put(context,new Hashtable());
}
}
/**
* Checks, if the specified String describes an existing
* outgoing context.
**/
public boolean isContext(String context)
{
if(context == null)
return false;
return outgoingContexts.get(context) != null;
}
/**
* Removes the specified outgoing context.
**/
public void removeContext(String context)
{
outgoingContexts.remove(context);
outgoingContextInvolved.remove(context);
}
/**
* Adds the specified remote object to the specified outgoing context.
**/
public UNL addToContext(String context, UNL remote)
{
if(context == null || remote == null)
return null;
remote = remote.addContext(context);
addToContext(remote);
return remote;
}
/**
* Adds the specified remote object to an implicite given context.
* Note: UNLs may contain contexts.
**/
public void addToContext(UNL remote)
{
if(remote == null)
return;
String context = remote.getContext();
if(context == null)
return;
Hashtable hash = (Hashtable)outgoingContextInvolved.get(context);
if(hash == null)
{
createContext(context);
hash = (Hashtable)outgoingContextInvolved.get(context);
}
if(hash.get(remote.withoutContext()) == null)
{
// a new involved peer
hash.put(remote.withoutContext(),remote);
// send em the complete context
hash = (Hashtable)outgoingContexts.get(context);
String name;
for(Enumeration e = hash.keys();e.hasMoreElements();)
{
name = (String)e.nextElement();
assignVariable(remote,name,(Value)hash.get(name),false);
}
}
return;
}
/**
* Removes the specified remote object from the specified outgoing context.
**/
public void removeFromContext(String context, UNL remote)
{
if(context == null || remote == null)
return;
remote = remote.addContext(context);
removeFromContext(remote);
}
/**
* Removes the specified remote object from the implicite given context.
* Note: UNLs may contain contexts.
**/
public void removeFromContext(UNL remote)
{
if(remote == null)
return;
String context = remote.getContext();
if(context == null)
return;
Hashtable hash = (Hashtable)outgoingContextInvolved.get(context);
if(hash == null)
return;
hash.remove(remote.withoutContext());
}
/**
* Assigns the given Value to the specified variable for the
* specified outgoing context.
**/
public void assignVariable(String context, String name, Value value, //
boolean immediately)
{
if(context == null || name == null)
return;
// get all already connected remotes, assign that there
Hashtable hash = (Hashtable)outgoingContextInvolved.get(context);
if(hash == null)
{
createContext(context);
hash = (Hashtable)outgoingContextInvolved.get(context);
}
for(Enumeration e = hash.elements();e.hasMoreElements();)
assignVariable((UNL)e.nextElement(),name,value,immediately);
// assign it to our context-store too for further connected remotes
hash = (Hashtable)outgoingContexts.get(context);
hash.put(name,value);
}
/**
* Augments the given Value to the specified variable for the
* specified outgoing context.
**/
public void augmentVariable(String context, String name, Value value, //
boolean immediately)
{
if(context == null || name == null)
return;
// get all already connected remotes, augment that there
Hashtable hash = (Hashtable)outgoingContextInvolved.get(context);
if(hash == null)
{
createContext(context);
hash = (Hashtable)outgoingContextInvolved.get(context);
}
for(Enumeration e = hash.elements();e.hasMoreElements();)
augmentVariable((UNL)e.nextElement(),name,value,immediately);
// augment it to our context-store too for further connected remotes
hash = (Hashtable)outgoingContexts.get(context);
Value v = (Value)hash.get(name);
if(v == null)
v = new Value();
v.augment(value.toString());
}
/**
* Diminishes the given Value from the specified variable for the
* specified outgoing context.
**/
public void diminishVariable(String context, String name, Value value, //
boolean immediately)
{
if(context == null || name == null)
return;
// get all already connected remotes, diminish that there
Hashtable hash = (Hashtable)outgoingContextInvolved.get(context);
if(hash == null)
{
createContext(context);
hash = (Hashtable)outgoingContextInvolved.get(context);
}
for(Enumeration e = hash.elements();e.hasMoreElements();)
diminishVariable((UNL)e.nextElement(),name,value,immediately);
// diminish it to our context-store too for further connected remotes
hash = (Hashtable)outgoingContexts.get(context);
Value v = (Value)hash.get(name);
if(v == null)
return;
v.diminish(value);
if(v.toString().length() <= 0)
hash.remove(name);
}
/**
* Removes the specified variable from the variable buffer for
* the specified outgoing context. It does not tell any peer about that.
* That means, that new peers don't get this variable any more.
**/
public void removeVariable(String context, String name)
{
if(context == null || name == null)
return;
Hashtable hash = (Hashtable)outgoingContexts.get(context);
if(hash == null)
return;
hash.remove(name);
}
/**
*
**/
private void setVariable(UNL remote, VariableModifier modifier, //
boolean immediately)
{
if(modifier == null)
return;
if(remote == null)
{
// broadcast
// set it to our known variables
Value value = (Value)knownVars.get(modifier.getName());
Value v = modifier.getValue();
if(value == null)
{
value = new Value();
knownVars.put(modifier.getName(),value);
}
if(v == null)
v = new Value();
value.handle(modifier.getGlyph(),v.toString());
if(value.toString().length() <= 0)
{
knownVars.remove(modifier.getName());
modifier = new VariableModifier(modifier.getGlyph(),//
modifier.getName(),null);
}
// and apply it to all open connections
for(Enumeration e = addresses.keys();e.hasMoreElements();)
setVariable((UNL)e.nextElement(),modifier,immediately);
}
else
{
// unicast
Vector modifiers = (Vector)outgoings.get(remote);
if(modifiers == null)
{
modifiers = new Vector();
outgoings.put(remote,modifiers);
}
modifiers.addElement(modifier);
if(immediately)
{
String prefix = null;
switch(modifier.getGlyph())
{
case VariableModifier.GLYPH_SET:
prefix = setPrefix;
break;
case VariableModifier.GLYPH_ASSIGN:
prefix = assignPrefix;
break;
case VariableModifier.GLYPH_AUGMENT:
prefix = augmentPrefix;
break;
case VariableModifier.GLYPH_DIMINISH:
prefix = diminishPrefix;
break;
}
if(prefix != null)
try
{
send(remote,prefix + modifier.getName(),null,null);
}
catch(PSYCDeliveryException e)
{
}
}
}
}
/**
* Assigns the specified variable for the specified remote object with
* the specified Value.
* If the remote is null, it does the same for itself.
* This means, it will be sent to every new connected remote object.
**/
public void assignVariable(UNL remote, String name, Value value, //
boolean immediately)
{
setVariable(remote,//
new VariableModifier(VariableModifier.GLYPH_ASSIGN,name,value),//
immediately);
}
/**
* Augments the specified variable for the specified remote object with
* the specified Value.
* If the remote is null, it does the same for itself.
* This means, it will be sent to every new connected remote object.
**/
public void augmentVariable(UNL remote, String name, Value value, //
boolean immediately)
{
setVariable(remote,//
new VariableModifier(VariableModifier.GLYPH_AUGMENT,name,value),//
immediately);
}
/**
* Diminishes the specified variable for the specified remote object with
* the specified Value.
* If the remote is null, it does the same for itself.
**/
public void diminishVariable(UNL remote, String name, Value value, //
boolean immediately)
{
setVariable(remote,//
new VariableModifier(VariableModifier.GLYPH_DIMINISH,name,value),//
immediately);
}
/**
* Queries the specified variable for the specified remote object.
* If the remote is null, it does the same for itself.
* This means, it will be sent to every new connected remote object.
**/
public void queryVariable(UNL remote, String name) //
throws PSYCDeliveryException
{
setVariable(remote,//
new VariableModifier(VariableModifier.GLYPH_QUERY,name,null),true);
}
/**
*
**/
private String preparePacket(String method, String body, //
Hashtable tempVars, Vector globVars)
{
StringBuffer packet = new StringBuffer();
packet.append(ModifierParser.writeHeader(globVars));
packet.append(ModifierParser.writeHeader(tempVars));
if(globVars != null)
globVars.removeAllElements();
if(method != null)
packet.append(method);
if(body != null)
{
packet.append(VariableModifier.EOL);
packet.append(body);
}
else
if(packet.length() > 0 && //
packet.charAt(packet.length() - 1) == VariableModifier.EOL)
packet.setLength(packet.length() - 1);
return packet.toString();
}
/**
* Sends the specified message (method and body) to the specified
* remote object and sets temporarily for this message the
* specified variables. tempVars contains a Map of String variableName
* to Value variableValue.
**/
public void send(UNL remote, String method, String body, //
Hashtable tempVars) throws PSYCDeliveryException
{
if(remote == null)
throw new PSYCDeliveryException(//
PSYCDeliveryException.NO_TARGET);
if(remote.getContext() != null)
{
if(tempVars == null)
tempVars = new Hashtable();
tempVars.put(contextTag,remote.getContext());
}
String packet = preparePacket(method,body,//
tempVars,(Vector)outgoings.get(remote));
synchronized(this)
{
gotException = null;
mmpCenter.send(getAddress(remote),new MMPPacket(null,packet));
if(gotException != null)
throw gotException;
}
}
/**
* Sends the specified message (method and body) to the specified
* context and sets temporarily for this message the
* specified variables. tempVars contains a Map of String variableName
* to Value variableValue.
* It ignores errors if they occure in sending to single context members.
**/
public void send(String context, String method, String body, //
Hashtable tempVars)
{
if(context == null)
return;
Hashtable hash = (Hashtable)outgoingContextInvolved.get(context);
if(hash == null)
return;
for(Enumeration e = hash.elements();e.hasMoreElements();)
try
{
send((UNL)e.nextElement(),method,body,tempVars);
}
catch(PSYCDeliveryException ex)
{
}
}
/**
* Sends the specified message (method and body) to the specified
* remote object.
**/
public void send(UNL remote, String method, String body) //
throws PSYCDeliveryException
{
send(remote,method,body,null);
}
/**
* Sends the specified message (method and body) to the specified
* context.
* It ignores errors if they occure in sending to single context members.
**/
public void send(String context, String method, String body)
{
if(context == null)
return;
Hashtable hash = (Hashtable)outgoingContextInvolved.get(context);
if(hash == null)
return;
for(Enumeration e = hash.elements();e.hasMoreElements();)
try
{
send((UNL)e.nextElement(),method,body);
}
catch(PSYCDeliveryException ex)
{
}
}
/**
* Sends the specified message (method, body and temporarily set variables)
* to the specified remote object but only, if the object supports the
* specified package.
**/
public void sendChecked(UNL remote, String packageName, //
String method, String body, Hashtable tempVars) //
throws PSYCDeliveryException
{
if(!understandsPackage(remote,packageName))
throw new PSYCDeliveryException(PSYCDeliveryException.NOT_SUPPORTED);
send(remote,method,body,tempVars);
}
/**
* Sends the specified message (method and body) to the specified remote
* object but only, if the object supports the specified package.
**/
public void sendChecked(UNL remote, String packageName, //
String method, String body) throws PSYCDeliveryException
{
sendChecked(remote,packageName,method,body,null);
}
}