[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: New problem



Yes, I knew I wuld be confusing :)  What I called the server below is the ozone
client.  When I moved the code to the ozone client it worked fine.  Let me say
that this is a very isolated case.  I know how to use ozone, and It has worked
flawlessly so far except for this case.  Maybe it had something to do with the
number of parameters or something, I do not know.  I have attached the source
files in question.

Server.java is the ozone client and raceImpl.java the ozone remote class.  I
*do* rference the objects via the proxy interface I just forgot that when typing
the last note.  osendMail() in Server is the orginal attempt and sendMail() is
what I got to work.

Tim

Falko Braeutigam wrote:

> Tim Brown wrote:
> >
> > This one is difficult to describe but I will try...
> >
> > I have a call from my game server like:
> >
> >     raceImpl_Int rc;
> >     ... get rc
> >     rc.sendMail(Integer fr, Integer fg,  Integer r, Integer
> Ha... seems like you need primitive types. I have finished this yesterday ;)
>
> > g, String text); // prototype shown for clarity
> >     ^^ at this point the String text has a value...
> >
> >     In raceImpl:
> >     System.err.println("text-" + text);
> >     ^^ at this point text = null !!
> >
> >     I have debugged the hell out of it and my info is
> > accurate..  The other parameters are OK.
> Hmmm.. wait a moment, I will check this... [back from my first test] no
> problems. I've passed a String as parameter to a proxy method from the client
> side. Your game server is a client to the ozone server, right?
>
> But why, if this example code is from the client side, you are using a *Impl
> class? On the client there should _only_ be proxies.
>
> >     When I moved the code over to the server and loaded the
> > raceImpl_Int mailbox object from there it worked.  This is
> > very tedious however.
> What does this mean, you have moved the code to the server? If it _is_ a
> persistent class, it _must_ be in the server.
>
> > What is wrong with parameter passing?  The proxy object
> > looks ok as well.
> >
> > If you want to trace through my code in detail it is at:
> > http://www.incenter.org/ngb/NEWGB_db.tar.gz
> If possible, we should try to figure out what happens by sending one or two
> more emails first. (I takes me to much time to understand your code)
>
> > Falko: this is my source as of this bugs happening.  I am
> > generally having a ball coding the game.  I have started
> > making all objects inside ozone remote objects ozone remote
> > as well.  This is how I ran across this bug.
> [totally confused] All objects inside ozone implement the OzoneRemote
> interface because the remote interfaces extend OzoneRemote...
>
> Here is a picture about the classes and interfaces to deal with when building
> an ozone app. On the left is the server and on the right the client. ~ are
> interfaces and - are classes. "Higher" classes/interfaces extend "lower"
> ones.
>
>                                 ###########
>                            ...> # OPP     #.............
>                           .     ###########             .
>                          .              ^                .
>                         .               .                 .
>         ---------------                 .               ---------------
>         *Impl                           .               *Impl_Proxy
>         ---------------                 .               ---------------
>            |            \       ~~~~~~~~~~~~~~~~~~     /        |
>            |             -----  <remote interface>  ---         |
>         ---------------         ~~~~~~~~~~~~~~~~~~      ---------------
>         OzoneObject                |                    OzoneProxy
>         ---------------            |                    ---------------
>            |                    ~~~~~~~~~~~~~~~~~~
>            |                    OzoneRemote
>         ~~~~~~~~~~~~~~~         ~~~~~~~~~~~~~~~~~~
>         OzoneCompatible
>         ~~~~~~~~~~~~~~~
>
> The only thing you have to do is to write your *Impl code and put all methods
> that should be accessible from the client in the <remote interface>. OPP
> takes *Impl and <remote interface> and generates the proxy class. Then you
> can create object in the databse and controll them via proxy because both,
> *Impl and *Impl_Proxy implementing the |remote interface>. Thats it.
>
> Tim?
>
> Regards,
> Falko
> --
> ______________________________________________________________________
> Falko Braeutigam                         mailto:falko@softwarebuero.de
> softwarebuero m&b (SMB)                    http://www.softwarebuero.de

--
Tim Brown
URL: http://www.incenter.org


// Server code

import java.net.*;
import java.io.*;
import java.awt.*;
import java.util.*;
import com.sun.java.swing.*;
import com.sun.java.swing.tree.*;
import DE.softwarebuero.ozone.*;
import DE.softwarebuero.DxLib.*;

public class Server extends Thread {
    public final static int DEFAULT_PORT = 2030;
    protected int port;
    protected ServerSocket listen_socket;
    protected ThreadGroup threadgroup;
    protected List connection_list;
    protected JLabel status;
    protected Vector connections;
    protected Vulture vulture;
    public RemoteDatabase db;
    public boolean dbStatus;
    private gIndexImpl_Int gameIndex;
    private commandsImpl_Int cmds;
    public String gameName;
    public boolean keepGoing;

    public boolean sendMail(int frnum, int fgnum, 
			    int rnum, int gnum, 
			    String text) {
	Enumeration en = gameIndex.getRaces().elements();
	int i = 0;
	while(en.hasMoreElements()) {
	    raceImpl_Int rc = (raceImpl_Int)en.nextElement();
	    if(rc.getKey().getRaceNum().intValue() == rnum) {
		governorImpl_Int gv = rc.getGovernor(new Integer(gnum));
		if(gv == null) {
		    addMsg("No such gov");
		    return false;
		}
		Integer n = gv.getMailbox().size();
		mesgImpl_Int msg = null;
		try {
		    msg = (mesgImpl_Int)db.createObject("mesgImpl", 0, 
							rc.getKey().getString() + "/m/" +
							gv.getDBName() + "/" + n);
		} catch(Exception e) {
		    addMsg("Error in " +
			   rc.getName() + ".sendMail()::" + e);
		    return false;
		}
		msg.setFrom("" + frnum +
			    "/" + fgnum);
		addMsg("txt=" + text);
		msg.setBody(text);
		addMsg("msg=" + msg.getBody());
		Date d = new Date();
		msg.setDateSent(d);
		msg.setDateReceived(d);
		gv.addMail(msg);
		return true;
	    }
	}
	addMsg("No such race");
	return false;
    }

    public boolean osendMail(int frnum, int fgnum, 
			    int rnum, int gnum, String text) {
	Enumeration en = gameIndex.getRaces().elements();
	int i = 0;
	while(en.hasMoreElements()) {
	    raceImpl_Int rc = (raceImpl_Int)en.nextElement();
	    if(rc.getKey().getRaceNum().intValue() == rnum) {
		rc.sendMail(new Integer(frnum),
			    new Integer(fgnum),
			    new Integer(gnum),
			    text);
		return true;
	    }
	}
	return false;
    }

    // Exit with an error message, when an exception occurs.
    public static void fail(Exception e, String msg) {
	System.err.println(msg + ": " +	 e);
	System.exit(1);
    }

    public void broadcast(governorImpl_Int gov, String msg) {
	Enumeration en = connections.elements();
	while(en.hasMoreElements()) {
	    Connection con = (Connection)en.nextElement();
	    con.rcvBroadcast(gov, msg);
	}
    }

    public commandsImpl_Int getCommands() {
	try {
	    return (commandsImpl_Int)db.objectForName(OZ_newgame.COMMANDS);
	} catch(Exception e) {
	    System.err.println("server.getCommands()::" + e);
	    return null;
	}
    }
    
    public void addMsg(String msg) {
	try {
	    connection_list.add(msg);
	    connection_list.makeVisible(connection_list.getItemCount()-1);
	} catch(Exception e) {
	    System.err.println("Error in Server.addMsg()::" + e);
	}
    }
    
    public void logoff(raceImpl_Int race, governorImpl_Int gov) {
	gameIndex.removeSession(makeSessionKey(race, gov));
    }

    private String makeSessionKey(raceImpl_Int race, governorImpl_Int gov) {
	System.err.println(race.getDBName() +
	    "//" +
	    gov.getDBName());
	return race.getDBName() +
	    "//" +
	    gov.getDBName();
    }

    public void addSession(raceImpl_Int race, governorImpl_Int gov) {
	try {
	    sessionImpl_Int sess = (sessionImpl_Int)db.createObject("sessionImpl",0, 
								    makeSessionKey(race, gov));
	    sess.setRace(race);
	    sess.setGovernor(gov);
	    sess.setKey(makeSessionKey(race, gov));
	    gameIndex.addSession(sess);
	} catch(Exception e) {
	    System.err.println("Error adding session::" + e);
	}
    }

    public raceImpl_Int getRace(Integer raceid, String racepass, String govpass) {
	raceKey rk = new raceKey(new gameKey(gameName),
				 raceid);
	raceImpl_Int race = gameIndex.getRace(rk);
	if(race == null) {
	    System.err.println("No race for:" +
			       rk.getString());
	    return null;
	}
	// now see if passwords are right
	if(!race.loginGovernor(racepass, govpass).booleanValue())
	    return null;
	return race;
    }

    private boolean initDB() {
	if(!openDB())
	    return false;
	// get gindex
	try {
	    gameIndex = (gIndexImpl_Int)db.objectForName("gameIndex");
	    if(gameIndex == null)
		return false;
	    gameIndex.resetSessions();
	    return true;
	} catch(Exception e) {
	    System.err.println("Error::" + e);
	    return false;
	}
    }

    private boolean openDB() {
	// open database
        db = new RemoteDatabase();
        try {
            //  open the connection on localhost at port 3333
            db.open ("localhost", 3333);
            
            // reload our database classes if changed them
            db.reloadClasses();
	    return true;

        } catch(Exception e) {
	    dbStatus = false;
	    JOptionPane.showMessageDialog(null
                                        ,"Error opening database"
                                        ,"Database Error"
                                        ,JOptionPane.ERROR_MESSAGE);
            try {
                db.close();
            } catch (Exception ex) {
                return false;
            }
	    return true;
        }

    }
    private boolean closeDB() {
	try {
	    System.err.println("Closing database");
	    db.close();
	    return true;
	} catch(Exception e) {
	    System.err.println(e + "::Error closing database");
	    return false;
	}
    }

    // Create a ServerSocket to listen for connections on;  start the thread.
    public Server(int port, String gname) {
	// Create our server thread with a name.
	super("Server");

	gameName = gname;

	// open database
	if(!initDB()) {
	    System.err.println("Error opening database");
	    System.exit(2);
	}

	if (port == 0) port = DEFAULT_PORT;
	this.port = port;
	try { listen_socket = new ServerSocket(port); }
	catch (IOException e) { fail(e, "Exception creating server socket"); }
	try { listen_socket.setSoTimeout(1000); }
	catch(Exception e) {;}

	// Create a threadgroup for our connections
	threadgroup = new ThreadGroup("Server Connections");

	// Create a window to display our connections in
	JFrame f = new JFrame("Server Status");
	connection_list = new List();
	status = new JLabel();
	JButton btnQuit = new JButton("Quit");
	btnQuit.addActionListener (new java.awt.event.ActionListener () {
            public void actionPerformed (java.awt.event.ActionEvent evt) {
                btnQuitActionPerformed (evt);
            }
        });

	
	f.getContentPane().add("North", btnQuit);
	f.getContentPane().add("Center", connection_list);
	f.getContentPane().add("South", status);
	f.setSize(400, 200);
	f.show();
    
	// Initialize a vector to store our connections in
	connections = new Vector();

	// Create a Vulture thread to wait for other threads to die.
	// It starts itself automatically.
	vulture = new Vulture(this);

	// Start the server listening for connections
	this.start();
    }

    private void btnQuitActionPerformed (java.awt.event.ActionEvent evt) {
	keepGoing = false;
    }
	
    // The body of the server thread.  Loop forever, listening for and
    // accepting connections from clients.  For each connection,
    // create a Connection object to handle communication through the
    // new Socket.  When we create a new connection, add it to the
    // Vector of connections, and display it in the List.  Note that we
    // use synchronized to lock the Vector of connections.  The Vulture
    // class does the same, so the vulture won't be removing dead
    // connections while we're adding fresh ones.
    public void run() {
	keepGoing = true;
	while(keepGoing) {
	    try {
		Socket client_socket = listen_socket.accept();
		Connection c = new Connection(client_socket, threadgroup,
					      3, vulture);
		// prevent simultaneous access.
		synchronized (connections) {
		    connections.addElement(c);
		    connection_list.addItem(c.toString());
		    
		}
	    } catch(Exception e) {
		if(!e.toString().startsWith("java.io.InterruptedIOException")) {
		    System.err.println(e);
		    break;
		} 
	    }
	}
	closeDB();
	System.exit(0);
	
    }

    // Start the server up, listening on an optionally specified port
    public static void main(String[] args) {
	int port = 0;
	String gname = null;
	if (args.length == 1) {
	    try { gname = args[0]; }
	    catch(Exception e) {
		System.err.println("Error::" + e);
		System.exit(3);
	    }
	}
	System.err.println("Game:" + gname);

	try { port = Integer.parseInt(args[1]); }
	catch (Exception e) { port = 0; }

	new Server(port, gname);
    }
}


class CmdBase {
  
}
// race object

import java.io.*;
import java.lang.*;
import java.net.*;
import java.util.*;
import com.sun.java.swing.tree.*;
import DE.softwarebuero.ozone.*;
import DE.softwarebuero.DxLib.*;

public class raceImpl extends OzoneObject implements raceImpl_Int
{

    
    // race attributes

    planetImpl_Int homePlanet;
    
    /**
       * Get the value of homePlanetKey.
       * @return Value of homePlanetKey.
       */
    public planetImpl_Int getHomePlanet() {return homePlanet;}
    
    /**
       * Set the value of homePlanetKey.
       * @param v  Value to assign to homePlanetKey.
       */
    public void setHomePlanet(planetImpl_Int  v) {
	lock();
	this.homePlanet = v;
    }
    

    public String getDBName() {
	return key.getString();
    }

    raceKey key;
    
    /**
       * Get the value of key.
       * @return Value of key.
       */
    public raceKey getKey() {return key;}
    
    /**
       * Set the value of key.
       * @param v  Value to assign to key.
       */
    public void setKey(raceKey  v) {
	lock();
	this.key = v;
    }
    

    Integer playernum;
    
    /**
       * Get the value of playernum.
       * @return Value of playernum.
       */
    public Integer getPlayernum() {return playernum;}
    
    /**
       * Set the value of playernum.
       * @param v  Value to assign to playernum.
       */
    public void setPlayernum(Integer  v) {
	lock();
	this.playernum = v;
    }
    

    String name;
    
    /**
       * Get the value of name.
       * @return Value of name.
       */
    public String getName() {return name;}
    
    /**
       * Set the value of name.
       * @param v  Value to assign to name.
       */
    public void setName(String  v) {
	lock();
	this.name = v;
    }
    

    String password;
    
    /**
       * Get the value of password.
       * @return Value of password.
       */
    public String getPassword() {return password;}
    
    /**
       * Set the value of password.
       * @param v  Value to assign to password.
       */
    public void setPassword(String  v) {
	lock();
	this.password = v;
    }
    

    String personal;
    
    /**
       * Get the value of personal.
       * @return Value of personal.
       */
    public String getPersonal() {return personal;}
    
    /**
       * Set the value of personal.
       * @param v  Value to assign to personal.
       */
    public void setPersonal(String  v) {
	lock();
	this.personal = v;
    }
    

    String motto;
    
    /**
       * Get the value of motto.
       * @return Value of motto.
       */
    public String getMotto() {return motto;}
    
    /**
       * Set the value of motto.
       * @param v  Value to assign to motto.
       */
    public void setMotto(String  v) {
	lock();
	this.motto = v;
    }
    

    Boolean absorb;
    
    /**
       * Get the value of absorb.
       * @return Value of absorb.
       */
    public Boolean getAbsorb() {return absorb;}
    
    /**
       * Set the value of absorb.
       * @param v  Value to assign to absorb.
       */
    public void setAbsorb(Boolean  v) {
	lock();
	this.absorb = v;
    }
    

    Boolean collectiveIQ;
    
    /**
       * Get the value of collectiveIQ.
       * @return Value of collectiveIQ.
       */
    public Boolean getCollectiveIQ() {return collectiveIQ;}
    
    /**
       * Set the value of collectiveIQ.
       * @param v  Value to assign to collectiveIQ.
       */
    public void setCollectiveIQ(Boolean  v) {
	lock();
	this.collectiveIQ = v;
    }
    

    Boolean pods;
    
    /**
       * Get the value of pods.
       * @return Value of pods.
       */
    public Boolean getPods() {return pods;}
    
    /**
       * Set the value of pods.
       * @param v  Value to assign to pods.
       */
    public void setPods(Boolean  v) {
	lock();
	this.pods = v;
    }
    

    Double fightRating;
    
    /**
       * Get the value of fightRating.
       * @return Value of fightRating.
       */
    public Double getFightRating() {return fightRating;}
    
    /**
       * Set the value of fightRating.
       * @param v  Value to assign to fightRating.
       */
    public void setFightRating(Double  v) {
	lock();
	this.fightRating = v;
    }
    

    Double IQ;
    
    /**
       * Get the value of IQ.
       * @return Value of IQ.
       */
    public Double getIQ() {return IQ;}
    
    /**
       * Set the value of IQ.
       * @param v  Value to assign to IQ.
       */
    public void setIQ(Double  v) {
	lock();
	this.IQ = v;
    }
    

    Double IQ_limit;
    
    /**
       * Get the value of IQ_limit.
       * @return Value of IQ_limit.
       */
    public Double getIQ_limit() {return IQ_limit;}
    
    /**
       * Set the value of IQ_limit.
       * @param v  Value to assign to IQ_limit.
       */
    public void setIQ_limit(Double  v) {
	lock();
	this.IQ_limit = v;
    }
    

    Integer sexes;
    
    /**
       * Get the value of sexes.
       * @return Value of sexes.
       */
    public Integer getSexes() {return sexes;}
    
    /**
       * Set the value of sexes.
       * @param v  Value to assign to sexes.
       */
    public void setSexes(Integer  v) {
	lock();
	this.sexes = v;
    }
    

    Double fertilize;
    
    /**
       * Get the value of fertilize.
       * @return Value of fertilize.
       */
    public Double getFertilize() {return fertilize;}
    
    /**
       * Set the value of fertilize.
       * @param v  Value to assign to fertilize.
       */
    public void setFertilize(Double  v) {
	lock();
	this.fertilize = v;
    }
    

    Double adventurism;
    
    /**
       * Get the value of adventurism.
       * @return Value of adventurism.
       */
    public Double getAdventurism() {return adventurism;}
    
    /**
       * Set the value of adventurism.
       * @param v  Value to assign to adventurism.
       */
    public void setAdventurism(Double  v) {
	lock();
	this.adventurism = v;
    }
    

    Double birthrate;
    
    /**
       * Get the value of birthrate.
       * @return Value of birthrate.
       */
    public Double getBirthrate() {return birthrate;}
    
    /**
       * Set the value of birthrate.
       * @param v  Value to assign to birthrate.
       */
    public void setBirthrate(Double  v) {
	lock();
	this.birthrate = v;
    }
    

    Double mass;
    
    /**
       * Get the value of mass.
       * @return Value of mass.
       */
    public Double getMass() {return mass;}
    
    /**
       * Set the value of mass.
       * @param v  Value to assign to mass.
       */
    public void setMass(Double  v) {
	lock();
	this.mass = v;
    }
    

    Double metabolism;
    
    /**
       * Get the value of metabolism.
       * @return Value of metabolism.
       */
    public Double getMetabolism() {return metabolism;}
    
    /**
       * Set the value of metabolism.
       * @param v  Value to assign to metabolism.
       */
    public void setMetabolism(Double  v) {
	lock();
	this.metabolism = v;
    }
    

    Hashtable likes;
    
    /**
       * Get the value of likes.
       * @return Value of likes.
       */
    public Hashtable getLikes() {return likes;}
    
    /**
       * Set the value of likes.
       * @param v  Value to assign to likes.
       */
    public void setLikes(Hashtable  v) {
	lock();
	this.likes = v;
    }
    

    atmosphere atmosphere;
    
    /**
       * Get the value of atmosphere.
       * @return Value of atmosphere.
       */
    public atmosphere getAtmosphere() {return atmosphere;}
    
    /**
       * Set the value of atmosphere.
       * @param v  Value to assign to atmosphere.
       */
    public void setAtmosphere(atmosphere  v) {
	lock();
	this.atmosphere = v;
    }
    

    Boolean dissolved;
    
    /**
       * Get the value of dissolved.
       * @return Value of dissolved.
       */
    public Boolean getDissolved() {return dissolved;}
    
    /**
       * Set the value of dissolved.
       * @param v  Value to assign to dissolved.
       */
    public void setDissolved(Boolean  v) {
	lock();
	this.dissolved = v;
    }
    

    raceType raceType;
    
    /**
       * Get the value of raceType.
       * @return Value of raceType.
       */
    public raceType getRaceType() {return raceType;}
    
    /**
       * Set the value of raceType.
       * @param v  Value to assign to raceType.
       */
    public void setRaceType(raceType  v) {
	lock();
	this.raceType = v;
    }
    

    Boolean monitor;
    
    /**
       * Get the value of monitor.
       * @return Value of monitor.
       */
    public Boolean getMonitor() {return monitor;}
    
    /**
       * Set the value of monitor.
       * @param v  Value to assign to monitor.
       */
    public void setMonitor(Boolean  v) {
	lock();
	this.monitor = v;
    }
    

    Vector translations;
    
    /**
       * Get the value of translations.
       * @return Value of translations.
       */
    public Vector getTranslations() {return translations;}
    
    /**
       * Set the value of translations.
       * @param v  Value to assign to translations.
       */
    public void setTranslations(Vector  v) {
	lock();
	this.translations = v;
    }
    

    Vector relations;
    
    /**
       * Get the value of relations.
       * @return Value of relations.
       */
    public Vector getRelations() {return relations;}
    
    /**
       * Set the value of relations.
       * @param v  Value to assign to relations.
       */
    public void setRelations(Vector  v) {
	lock();
	this.relations = v;
    }
    

    Long morale;
    
    /**
       * Get the value of morale.
       * @return Value of morale.
       */
    public Long getMorale() {return morale;}
    
    /**
       * Set the value of morale.
       * @param v  Value to assign to morale.
       */
    public void setMorale(Long  v) {
	lock();
	this.morale = v;
    }
    

    shipImpl_Int govShip;
    
    /**
       * Get the value of govShip.
       * @return Value of govShip.
       */
    public shipImpl_Int getGovShip() {return govShip;}
    
    /**
       * Set the value of govShip.
       * @param v  Value to assign to govShip.
       */
    public void setGovShip(shipImpl_Int  v) {this.govShip = v;}
    

    Integer controlledPlanets;
    
    /**
       * Get the value of controlledPlanets.
       * @return Value of controlledPlanets.
       */
    public Integer getControlledPlanets() {return controlledPlanets;}
    
    /**
       * Set the value of controlledPlanets.
       * @param v  Value to assign to controlledPlanets.
       */
    public void setControlledPlanets(Integer  v) {
	lock();
	this.controlledPlanets = v;
    }
    

    Double techFactor;
    
    /**
       * Get the value of techFactor.
       * @return Value of techFactor.
       */
    public Double getTechFactor() {return techFactor;}
    
    /**
       * Set the value of techFactor.
       * @param v  Value to assign to techFactor.
       */
    public void setTechFactor(Double  v) {
	lock();
	this.techFactor = v;
    }
    

    Vector discoveries;
    
    /**
       * Get the value of discoveries.
       * @return Value of discoveries.
       */
    public Vector getDiscoveries() {return discoveries;}
    
    /**
       * Set the value of discoveries.
       * @param v  Value to assign to discoveries.
       */
    public void setDiscoveries(Vector  v) {
	lock();
	this.discoveries = v;
    }
    

    public governorImpl_Int getGovernor(String gpass) {
	return (governorImpl_Int)governors.get(gpass);
    }
    
    public Boolean loginGovernor(String rpass, String gpass) {
	Boolean f = new Boolean(false);
	Boolean t = new Boolean(true);

	if(!rpass.equals(password))
	    return f;
	if(governors.get(gpass) == null)
	    return f;
	else 
	    return t;
    }

    Hashtable governors;
    
    /**
       * Get the value of governors.
       * @return Value of governors.
       */
    public Hashtable getGovernors() {return governors;}
    
    /**
       * Set the value of governors.
       * @param v  Value to assign to governors.
       */
    public void setGovernors(Hashtable  v) {
	lock();
	this.governors = v;
    }


    Hashtable stars;
    
    /**
       * Get the value of stars.
       * @return Value of stars.
       */
    public Hashtable getStars() {return stars;}
    
    /**
       * Set the value of stars.
       * @param v  Value to assign to stars.
       */
    public void setStars(Hashtable  v) {
	lock();
	this.stars = v;
    }
    

    public raceImpl() {
	playernum = null;
	key = null;
	governors = null;
    }

    public void construct(gameKey gkey, Integer num) {
	lock();
	playernum = num;
	key = new raceKey(gkey, num);
	governors = new Hashtable();
    }

    public governorImpl_Int getGovernor(Integer num) {
	Enumeration en = governors.elements();
	int i = 0;
	while(en.hasMoreElements()) {
	    governorImpl_Int gov = (governorImpl_Int)en.nextElement();
	    if(i == gov.getNum().intValue())
		return gov;
	}
	return null;
    }

    public void sendMail(Integer frnum, Integer fgnum, Integer gnum, String text) {
	governorImpl_Int gv = getGovernor(gnum);
	if(gv == null)
	    return;
	Integer n = gv.getMailbox().size();
	mesgImpl_Int msg = null;
	try {
	    msg = (mesgImpl_Int)database().createObject("mesgImpl", 0, 
							key.getString() + "/m/" +
							gv.getDBName() + "/" + n);
	} catch(Exception e) {
	    System.err.println("Error in " +
			       name + ".sendMail()::" + e);
	    return;
	}
	msg.setFrom("" + frnum +
		    "/" + fgnum);
	System.err.println("txt=" + text);
	msg.setBody(text);
	System.err.println("msg=" + msg.getBody());
	Date d = new Date();
	msg.setDateSent(d);
	msg.setDateReceived(d);
	gv.addMail(msg);
	return;
    }

    public void addGovernor(String gname, String gpass) {
	lock();
	int num = governors.size();
	try {
	    governorImpl_Int gov = (governorImpl_Int)database().createObject("governorImpl", 0,
									 getDBName() + "/" +
									 num);
	    gov.setDBName(getDBName() + "/" + num);
	    gov.construct(this, gname, gpass);
	    governors.put(gpass, gov);
	} catch(Exception e) {
	    System.err.println("Failed to add governor::" + e);
	}
    }

    public DefaultMutableTreeNode getTreeNode() {
	DefaultMutableTreeNode top = 
	    new DefaultMutableTreeNode(name +
				       " (" + playernum + ")");
	DefaultMutableTreeNode tnode = null, gnode = null;
	
	tnode = new DefaultMutableTreeNode("Personal: " + personal);
	top.add(tnode);
	tnode = new DefaultMutableTreeNode("Fight: " + fightRating);
	top.add(tnode);
	
	if(governors.size() > 0) {
	    gnode = new DefaultMutableTreeNode("Governors");
	    
	    Enumeration govs = governors.elements();
	    
	    governorImpl_Int gov = null;
	    while(govs.hasMoreElements()) {
		gov = (governorImpl_Int)govs.nextElement();
		gnode.add(new DefaultMutableTreeNode("Governor: " + gov.getName()));
	    }
	    top.add(gnode);
	}
	// display node for home planet
	tnode = new DefaultMutableTreeNode("Home Planet");
	tnode.add(new DefaultMutableTreeNode(homePlanet.getName()));
	top.add(tnode);

	return top;
    }
}