From: <sno...@us...> - 2006-04-19 08:58:03
|
Revision: 63 Author: snowdog_ Date: 2006-04-19 01:57:53 -0700 (Wed, 19 Apr 2006) ViewCVS: http://svn.sourceforge.net/openrpg/?rev=63&view=rev Log Message: ----------- Integrated message preliminary routing code into core. ORPGMessages must now contain a valid MessageAddress or the message send will fail with a DevConsole warning. ExampleClientModule has been updated to use a MessageAddress in its messages which have been directed to 'BROADCAST'. Eventually client sent broadcast messages will be dropped by the server. Only the server itself will be allowed to broadcast messages to all clients. Modified Paths: -------------- trunk/src/openrpg2/client/core/modules/ExampleClientModule.java trunk/src/openrpg2/common/core/engine/Engine.java trunk/src/openrpg2/common/core/engine/ModuleManager.java trunk/src/openrpg2/common/core/group/Group.java trunk/src/openrpg2/common/core/group/GroupManager.java trunk/src/openrpg2/common/core/route/AddressToken.java trunk/src/openrpg2/common/core/route/MessageAddress.java trunk/src/openrpg2/common/core/route/RouteManager.java Modified: trunk/src/openrpg2/client/core/modules/ExampleClientModule.java =================================================================== --- trunk/src/openrpg2/client/core/modules/ExampleClientModule.java 2006-04-18 22:54:17 UTC (rev 62) +++ trunk/src/openrpg2/client/core/modules/ExampleClientModule.java 2006-04-19 08:57:53 UTC (rev 63) @@ -25,12 +25,13 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; -import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import openrpg2.common.core.ORPGMessage; import openrpg2.common.core.engine.ModuleCommunicationException; +import openrpg2.common.core.route.AddressToken; +import openrpg2.common.core.route.MessageAddress; import openrpg2.common.module.ClientLoadable; import openrpg2.common.module.NetworkedModule; @@ -72,6 +73,10 @@ ORPGMessage msg = new ORPGMessage(); msg.setHandlerId("Popup"); msg.setHeader("PopText","ExampleClientModule is annoying you with a popup"); + + MessageAddress sendTo = new MessageAddress(); + sendTo.append(new AddressToken(AddressToken.BROADCAST,0)); //send to all clients + msg.setDestination(sendTo); try{ this.modCom.sendToNetwork(msg); }catch(ModuleCommunicationException e){ Modified: trunk/src/openrpg2/common/core/engine/Engine.java =================================================================== --- trunk/src/openrpg2/common/core/engine/Engine.java 2006-04-18 22:54:17 UTC (rev 62) +++ trunk/src/openrpg2/common/core/engine/Engine.java 2006-04-19 08:57:53 UTC (rev 63) @@ -112,6 +112,8 @@ moduleManager.registerGUIManager(guiManager); moduleManager.registerGroupManager(groupManager); moduleManager.registerNetwork(networkRelay); + routeManager = new RouteManager(moduleManager, networkRelay, groupManager, isClientMode()); + moduleManager.registerRouteManager(routeManager); try{ moduleManager.initialize(); }catch (NoNetworkHookException nnhe ){ @@ -129,9 +131,13 @@ System.exit(ORPGConstants.FATAL_NETWORK_MODULE_FAIL); } - routeManager = new RouteManager(moduleManager, networkRelay); + } + private boolean isClientMode(){ + return (OperationMode == ORPGConstants.OPMODE_CLIENT); + } + public void routeORPGMessageToNetwork(ORPGMessage msg){ routeManager.sendMessageToNetwork(msg); } Modified: trunk/src/openrpg2/common/core/engine/ModuleManager.java =================================================================== --- trunk/src/openrpg2/common/core/engine/ModuleManager.java 2006-04-18 22:54:17 UTC (rev 62) +++ trunk/src/openrpg2/common/core/engine/ModuleManager.java 2006-04-19 08:57:53 UTC (rev 63) @@ -28,6 +28,7 @@ import openrpg2.common.core.ORPGMessage; import openrpg2.common.core.group.GroupManager; import openrpg2.common.core.gui.GUIManager; +import openrpg2.common.core.route.RouteManager; import openrpg2.common.module.BaseModule; @@ -49,6 +50,7 @@ private ModuleLoader moduleLoader = null; private GUIManager guiManager = null; private GroupManager groupManager = null; + private RouteManager routeManager = null; private Logger log = Logger.getLogger(this.getClass().getName()); @@ -133,7 +135,15 @@ groupManager = m; } + /** + * Registers a RouteManager with the ModuleManager + * @param m Reference to the RouteManager object that will supply message routing serivices. + */ + public void registerRouteManager(RouteManager m){ + routeManager = m; + } + /** * Called to initialize the ModuleManager. Does a sanity check to make sure the * Network hook and module loader are present then initializes the ModuleManager @@ -311,11 +321,14 @@ * @throws openrpg2.common.core.engine.ModuleCommunicationException Thrown if network is not available. */ public void sendToNetwork( ORPGMessage msg ) throws ModuleCommunicationException{ - + if ( msg.getDestination() == null){ + log.warning("Message for module "+msg.getHandlerId()+" dropped due to missing address information."); + return; + } if ( ! isInitialized() ){ throw new ModuleCommunicationException("Network Not Available"); } - networkHook.putORPGMessage(msg); + routeManager.sendMessageToNetwork(msg); } Modified: trunk/src/openrpg2/common/core/group/Group.java =================================================================== --- trunk/src/openrpg2/common/core/group/Group.java 2006-04-18 22:54:17 UTC (rev 62) +++ trunk/src/openrpg2/common/core/group/Group.java 2006-04-19 08:57:53 UTC (rev 63) @@ -21,10 +21,9 @@ package openrpg2.common.core.group; -import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; -import java.util.Iterator; +import java.util.Vector; /** * Group represents a logical grouping of clients on the server. @@ -119,6 +118,25 @@ return (GroupMember)members.get(new Integer(id)); } + public Enumeration getMemberIds(){ + return members.keys(); + } + + public synchronized Vector getMembersByRole(int role){ + Vector v = new Vector(); + Enumeration e = members.elements(); + while(e.hasMoreElements()){ + GroupMember m = (GroupMember)e.nextElement(); + try { + MemberRole r = getRole(m); + if (r.equals(role)){ + v.add(new Integer(m.getNetworkId())); + } + } catch (InvalidMemberException ex) {} + } + return v; + } + public MemberRole getRole(GroupMember member) throws InvalidMemberException{ if(!members.containsKey(new Integer(member.getNetworkId()))){ throw new InvalidMemberException("No client with id "+member.getNetworkId()); @@ -153,7 +171,7 @@ } return (GroupMember)members.get(new Integer(id)); } - + //only available at package level (default visibility used) synchronized Enumeration getMembers(){ return members.elements(); Modified: trunk/src/openrpg2/common/core/group/GroupManager.java =================================================================== --- trunk/src/openrpg2/common/core/group/GroupManager.java 2006-04-18 22:54:17 UTC (rev 62) +++ trunk/src/openrpg2/common/core/group/GroupManager.java 2006-04-19 08:57:53 UTC (rev 63) @@ -97,6 +97,10 @@ return false; } + public synchronized Enumeration getClientList(){ + return clientList.keys(); + } + public synchronized boolean addMemberToGroup(int groupId, GroupMember m){ Integer gid = new Integer(groupId); if (!clientList.containsKey(new Integer(m.getNetworkId()))){ return false; } //sanity check @@ -220,9 +224,7 @@ checkGroupRemovable(g.getGroupId()); } //prune out client from clientList - clientList.remove(id); - - + clientList.remove(id); } public void DEBUG_PRINTCLIENTLIST(){ Modified: trunk/src/openrpg2/common/core/route/AddressToken.java =================================================================== --- trunk/src/openrpg2/common/core/route/AddressToken.java 2006-04-18 22:54:17 UTC (rev 62) +++ trunk/src/openrpg2/common/core/route/AddressToken.java 2006-04-19 08:57:53 UTC (rev 63) @@ -122,6 +122,14 @@ } /** + * Gets the state of the exclude flag of this AddressToken + * @return boolean. True only if exclude flag set. + */ + public boolean getExcluded(){ + return this.exclude; + } + + /** * Sets the target of the address. See predefined target constants in MessageAddress * @param target A single char representing the addressing target of this message * @return boolean. True if target setting was valid, false if target is not valid @@ -135,6 +143,15 @@ } /** + * Retrieves the target of this AddressToken. + * @return char target descriptor (see constants for AddressToken) + */ + public char getTarget(){ + return this.target; + } + + + /** * Sets the client or group id number. * @param id client or group id 'target' for this address object */ @@ -143,6 +160,15 @@ } /** + * Retrieves the id number associated with this AddressToken + * @return id number of the client or group relevant to the Target + */ + public int getId(){ + return this.id; + } + + + /** * Generates an encoded address string for this object * @return encoded message address String. */ @@ -204,7 +230,7 @@ /** * convert() serves as the counterpart to the encode() method. - * It converts address tokens as created by encode() back into MessageAddress objects. + * It converts address tokens as created by encode() back into MessageAddressToken objects. * This is a static method. * @param addressToken A single address token as generated by encode() or toString() * @throws openrpg2.common.core.route.InvalidMessageTargetException Thrown when errors occure while converting the message address Modified: trunk/src/openrpg2/common/core/route/MessageAddress.java =================================================================== --- trunk/src/openrpg2/common/core/route/MessageAddress.java 2006-04-18 22:54:17 UTC (rev 62) +++ trunk/src/openrpg2/common/core/route/MessageAddress.java 2006-04-19 08:57:53 UTC (rev 63) @@ -50,6 +50,13 @@ Vector address = new Vector(); } + /** + * Accesses the raw AddressTokens of this MessageAddress + */ + public Enumeration getTokens(){ + return address.elements(); + } + public Enumeration convert(String addressString){ clear(); AddressToken t = null; Modified: trunk/src/openrpg2/common/core/route/RouteManager.java =================================================================== --- trunk/src/openrpg2/common/core/route/RouteManager.java 2006-04-18 22:54:17 UTC (rev 62) +++ trunk/src/openrpg2/common/core/route/RouteManager.java 2006-04-19 08:57:53 UTC (rev 63) @@ -20,11 +20,19 @@ */ package openrpg2.common.core.route; +import java.util.Enumeration; import java.util.Observable; import java.util.Observer; +import java.util.Vector; import java.util.logging.Logger; import openrpg2.common.core.ORPGMessage; import openrpg2.common.core.engine.NetworkedModuleLocator; +import openrpg2.common.core.group.Group; +import openrpg2.common.core.group.GroupClient; +import openrpg2.common.core.group.GroupManager; +import openrpg2.common.core.group.InvalidGroupException; +import openrpg2.common.core.group.InvalidMemberException; +import openrpg2.common.core.group.Role; import openrpg2.common.core.network.NetworkMessageRelay; import openrpg2.common.core.network.NoObservableExistsException; @@ -41,15 +49,19 @@ private boolean runFlag = false; private Thread routingThread = null; private NetworkMessageRelay networkRelay = null; + private GroupManager groupManager = null; + private boolean inClientMode = false; private Object lock = new Object(); private Logger log = Logger.getLogger(this.getClass().getName()); /** - * Creates a new instance of RouteManager + * Creates a new instance of RouteManager */ - public RouteManager(NetworkedModuleLocator locatorRef, NetworkMessageRelay network) { + public RouteManager(NetworkedModuleLocator locatorRef, NetworkMessageRelay network, GroupManager groupManagerRef, boolean isClient) { //initialize the thread pool + groupManager = groupManagerRef; networkRelay = network; + inClientMode = isClient; try{ networkRelay.addMessageQueueObserver(this); }catch (NoObservableExistsException e){ @@ -80,27 +92,159 @@ }; routingThread.start(); } - + private void stop(){ runFlag = false; synchronized(lock){ lock.notify(); //wake this thread } - } + } - public void sendMessageToNetwork(ORPGMessage msg){ - RouteServiceThread sendThread = threadPool.getServiceThread(); - sendThread.send(msg); //hand message to RouteServiceThread and release the thread. - } + public void sendMessageToNetwork(ORPGMessage msg){ + if (msg == null ){ return;} //sanity check + //address resolution not required by client side routing + if (!inClientMode){ + msg = resolveMessageAddress(msg); + } + RouteServiceThread sendThread = threadPool.getServiceThread(); + sendThread.send(msg); //hand message to RouteServiceThread and release the thread. + } - //implements update method of Observer interface; - public void update(Observable o, Object arg){ - //only monitoring one queue (incoming from network) so doing no check on which Observable notified us. - synchronized(lock){ + /** + * This method resolves the supplied ORPGMessage address and loads the messages + * internal int[] of client destination ids. It handles removing duplicate references so only + * one copy of the message will be delivered to a given client. + */ + private ORPGMessage resolveMessageAddress(ORPGMessage msg){ + ORPGMessage m = msg; + MessageAddress a = msg.getDestination(); + log.fine("Resolving address for message address: "+a.toString()); + Vector validClients = new Vector(); + Enumeration tokens = a.getTokens(); + while( tokens.hasMoreElements()){ + AddressToken t = (AddressToken)tokens.nextElement(); + updateValidClientsVector(validClients, t); + } + + //build int[] of clients. + + return m; + } + + private void updateValidClientsVector(Vector v, AddressToken t){ + Vector currentToken = new Vector(); + //find out what kind of target is called for + char target = t.getTarget(); + switch(target){ + case(AddressToken.BROADCAST):{ + Enumeration clients = groupManager.getClientList(); + while( clients.hasMoreElements()){ + Integer i = (Integer)clients.nextElement(); + currentToken.add(new Integer(i.intValue())); //deep copy to protect original references + } + break; + } + case(AddressToken.ALL):{ + Group g; + try { g = groupManager.getGroup(t.getId()); + } catch (InvalidGroupException ex) { + log.fine("Invalid group id ("+t.getId()+") in message. Dropping token: "+t.toString()); + return; //bailout on this token and ignore + } + Enumeration members = g.getMemberIds(); + while (members.hasMoreElements()){ + Integer i = (Integer)members.nextElement(); + currentToken.add(new Integer(i.intValue())); //deep copy to protect original references + } + break; + } + case(AddressToken.CLIENT):{ + GroupClient c; + try { + c = groupManager.getClient(t.getId()); + } catch (InvalidMemberException ex) { + log.fine("Invalid member id ("+t.getId()+") in message. Dropping token: "+t.toString()); + return; //bailout on this token and ignore + } + currentToken.add(new Integer(c.getNetworkId())); + break; + } + case(AddressToken.GM):{ + Group g; + try { g = groupManager.getGroup(t.getId()); + } catch (InvalidGroupException ex) { + log.fine("Invalid group id ("+t.getId()+") in message. Dropping token: "+t.toString()); + return; //bailout on this token and ignore + } + currentToken.addAll(g.getMembersByRole(Role.ROLE_GM)); + break; + } + case(AddressToken.PLAYERS):{ + Group g; + try { g = groupManager.getGroup(t.getId()); + } catch (InvalidGroupException ex) { + log.fine("Invalid group id ("+t.getId()+") in message. Dropping token: "+t.toString()); + return; //bailout on this token and ignore + } + currentToken.addAll(g.getMembersByRole(Role.ROLE_PLAYER)); + break; + } + case(AddressToken.LURKERS):{ + Group g; + try { g = groupManager.getGroup(t.getId()); + } catch (InvalidGroupException ex) { + log.fine("Invalid group id ("+t.getId()+") in message. Dropping token: "+t.toString()); + return; //bailout on this token and ignore + } + currentToken.addAll(g.getMembersByRole(Role.ROLE_LURKER)); + break; + } + case(AddressToken.INVISIBLES):{ + Group g; + try { g = groupManager.getGroup(t.getId()); + } catch (InvalidGroupException ex) { + log.fine("Invalid group id ("+t.getId()+") in message. Dropping token: "+t.toString()); + return; //bailout on this token and ignore + } + currentToken.addAll(g.getMembersByRole(Role.ROLE_GHOST)); + break; + } + default:{return;} //default simply bails out and does nothing + }//end of switch statement + if (t.getExcluded()){ + v = excludeClientVector(v,currentToken); + }else{ + v = joinClientVectors(v,currentToken); + } + } + + private Vector joinClientVectors(Vector v1, Vector v2){ + Enumeration e = v2.elements(); + while(e.hasMoreElements()){ + Integer i = (Integer)e.nextElement(); + if (!v1.contains(i)){ + v1.add(i); + } + } + return v1; + } + + private Vector excludeClientVector(Vector originalVector, Vector excludeVector){ + Enumeration e = excludeVector.elements(); + while(e.hasMoreElements()){ + originalVector.remove((Integer)e.nextElement()); + } + return originalVector; + } + + //implements update method of Observer interface; + public void update(Observable o, Object arg){ + //only monitoring one queue (incoming from network) so doing no check on which Observable notified us. + synchronized(lock){ lock.notify(); //wake this thread } - } - + } + protected void finalize() { stop(); threadPool.shutdownThreads(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |