basic server stuff

buko [2002-06-18 12:41:20]
basic server stuff
Filename
server/scs/auth/AuthenticationService.java
server/scs/jc/Client.java
server/scs/jc/ClientEventHandler.java
server/scs/jc/ClientState.java
server/scs/jc/ConsoleLoggingService.java
server/scs/jc/NonAuthenticationService.java
server/scs/jc/SimplePersistenceService.java
server/scs/jc/command/Command.java
server/scs/jc/command/QuitCommand.java
server/scs/jc/command/WorldEntryCommand.java
server/scs/jc/command/WorldLoginCommand.java
server/scs/log/LoggingService.java
server/scs/metadata/Metadata.java
server/scs/metadata/MetadataService.java
server/scs/persist/ObjectID.java
server/scs/persist/PersistenceService.java
server/scs/persist/PersistentObject.java
server/scs/service/AbstractService.java
server/scs/service/Service.java
server/scs/service/ServiceContext.java
server/scs/service/ServiceException.java
server/scs/service/ServiceParam.java
server/scs/service/ServiceParamMap.java
server/scs/service/StartServer.java
server/scs/ws/UserInfo.java
server/scs/ws/UserInfoService.java
server/scs/ws/World.java
server/scs/ws/WorldService.java
server/scs/ws/WorldServiceEventHandler.java
server/scs/ws/XmlSerializable.java
server/scs/ws/data/Avatar.java
server/scs/ws/data/Door.java
server/scs/ws/data/LocatedWorldObject.java
server/scs/ws/data/MetadataWorldObject.java
server/scs/ws/data/RemoteRoom.java
server/scs/ws/data/Room.java
server/scs/ws/data/UserAvatar.java
server/scs/ws/data/WorldObject.java
server/scs/ws/view/LocatedView.java
server/scs/ws/view/Theme.java
server/scs/ws/view/View.java
server/scs/ws/view/render/ConeGeometry.java
server/scs/ws/view/render/CubeGeometry.java
server/scs/ws/view/render/CylinderGeometry.java
server/scs/ws/view/render/Geometry.java
server/scs/ws/view/render/PolygonGeometry.java
server/scs/ws/view/render/Render3DTextInstruction.java
server/scs/ws/view/render/RenderBillboardInstruction.java
server/scs/ws/view/render/RenderConstants.java
server/scs/ws/view/render/RenderFogEffectInstruction.java
server/scs/ws/view/render/RenderGeometryInstruction.java
server/scs/ws/view/render/RenderInstruction.java
server/scs/ws/view/render/RenderInstructionChain.java
server/scs/ws/view/render/RenderLightInstruction.java
server/scs/ws/view/render/RenderModelInstruction.java
server/scs/ws/view/render/RenderRotationInstruction.java
server/scs/ws/view/render/RenderScalingInstruction.java
server/scs/ws/view/render/RenderSoundInstruction.java
server/scs/ws/view/render/RenderSpeechInstruction.java
server/scs/ws/view/render/RenderTextureInstruction.java
server/scs/ws/view/render/RenderTranslationInstruction.java
server/scs/ws/view/render/SphereGeometry.java
diff --git a/server/scs/auth/AuthenticationService.java b/server/scs/auth/AuthenticationService.java
new file mode 100644
index 0000000..5d812db
--- /dev/null
+++ b/server/scs/auth/AuthenticationService.java
@@ -0,0 +1,39 @@
+package psl.chime4.server.scs.auth;
+
+import psl.chime4.server.scs.service.*;
+
+/**
+ * The AuthenticationService is responsible for authenticating users to see
+ * if they can enter or use another specific service.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public interface AuthenticationService extends Service
+{
+   /**
+    * Used when a client requests a new Authentication ticket.
+    *
+    * @param username name of the user
+    * @param ticket   an existing ticket that acts as proof
+    * @return <code>null</code> if the ticket is denied else
+    *          an array of bytes containing the new ticket for the user
+    * @throws ServiceException
+    *         if the service fails
+    **/
+   public byte[] createTicket(String username, byte[] ticket)
+      throws ServiceException;
+
+   /**
+    * Authenticate a user with the given name and proof of identity.
+    *
+    * @param username name of the user
+    * @param ticket   proof that the user is who she says she is
+    * @return <code>null</code> if the user can logon else a String object
+    *         explaining why the user can logon
+    * @throws ServiceException
+    *         if the service fails
+    **/
+   public String authenticate(String username, byte[] ticket)
+      throws ServiceException;
+}
\ No newline at end of file
diff --git a/server/scs/jc/Client.java b/server/scs/jc/Client.java
new file mode 100644
index 0000000..665ec4a
--- /dev/null
+++ b/server/scs/jc/Client.java
@@ -0,0 +1,121 @@
+package psl.chime4.server.scs.jc;
+
+import psl.chime4.server.scs.jc.command.*;
+import psl.chime4.server.ces.*;
+import psl.chime4.server.ces.elvin.*;
+import psl.chime4.server.scs.*;
+import psl.chime4.server.scs.service.*;
+import psl.chime4.server.scs.log.*;
+
+import java.util.*;
+import java.util.HashMap;
+import java.io.*;
+
+/**
+ * A simple test client.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class Client
+{
+   public EventService EventService = new ElvinEventService();
+   public EventHandler EventHandler;
+   public LoggingService LoggingService = new ConsoleLoggingService();
+   public Map commandMap = new HashMap();
+
+   /** state of the client **/
+   public ClientState state = new ClientState();
+
+   public static void main(String[] args) throws Exception
+   {
+      Client client = new Client();
+      client.inputLoop();
+   }
+
+   /**
+    * Default constructor to initialize the command map and start up the
+    * different services.
+    **/
+   public Client()
+   {
+      initializeCommandMap();
+      EventService.startup();
+      EventHandler = new ClientEventHandler(this);
+   }
+
+   /**
+    * Map all the supported commands to their textual equals.
+    **/
+   private void initializeCommandMap()
+   {
+      commandMap.put("quit", new QuitCommand());
+      commandMap.put("login", new WorldLoginCommand());
+      commandMap.put("enter_world", new WorldEntryCommand());
+   }
+
+   /**
+    * Main input loop to wait for input and execute commands.
+    **/
+   private void inputLoop() throws Exception
+   {
+      BufferedReader inputReader =
+         new BufferedReader(new InputStreamReader(System.in));
+
+      while (true)
+      {
+         System.out.print(">> ");
+         String input = inputReader.readLine();
+
+         // get the command, everything before 'command: <args>'
+         int colonPos = input.indexOf(':');
+         if (colonPos > 0)
+         {
+            String command = input.substring(0, colonPos);
+            String args = input.substring(colonPos + 1);
+
+            Command commandObj = (Command) commandMap.get(command);
+            if (commandObj == null)
+            {
+               output("No Such Command!");
+            } else
+            {
+               try
+               {
+                  commandObj.execute(this, args);
+               }
+               catch (Exception e)
+               {
+                  e.printStackTrace();
+                  output("Bad command syntax!");
+               }
+            }
+         } else
+         {
+            output("No Such Command!");
+         }
+      }
+   }
+
+   /**
+    * Print out something that will display on the client's main screen.
+    *
+    * @param msg String to display to the client
+    **/
+   public void output(String msg)
+   {
+      System.out.println("<< " + msg);
+   }
+
+   /**
+    * Get the state of the client.
+    *
+    * @return state of the client
+    **/
+   public ClientState getState()
+   {
+      return state;
+   }
+}
+
+
diff --git a/server/scs/jc/ClientEventHandler.java b/server/scs/jc/ClientEventHandler.java
new file mode 100644
index 0000000..39f4b54
--- /dev/null
+++ b/server/scs/jc/ClientEventHandler.java
@@ -0,0 +1,121 @@
+package psl.chime4.server.scs.jc;
+
+import psl.chime4.server.ces.*;
+import psl.chime4.server.scs.*;
+import psl.chime4.server.scs.ws.event.*;
+
+/**
+ * Event handler used for the client.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class ClientEventHandler implements EventHandler
+{
+   /** client who created us **/
+   private Client client;
+
+   /**
+    * Construct a new event handler to work for a specific client.
+    *
+    * @param client client who wants the event handler
+    * @throws IllegalArgumentException
+    *         if <code>client</code> is <code>null</code>
+    **/
+   public ClientEventHandler(Client client)
+   {
+      if (client == null)
+      {
+         String msg = "client cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      this.client = client;
+   }
+
+   /**
+    * Consume an event. If the event is passed, the handler can be sure that
+    * it recieved it because it met the necessary criteria.
+    *
+    * @param event Event that met the handler's criteria
+    */
+   public void handleEvent(Event event)
+   {
+      // log the event
+      client.LoggingService.info("CEH", "Recieved Event: " + event);
+
+      // switch on the event
+      WorldEvent wevent = WorldEventMapper.cesToWorld(event);
+
+      switch (wevent.EventCode)
+      {
+         case EventConstants.WorldLoginSuccess:
+            handleEvent((WorldLoginSuccessEvent) wevent);
+            break;
+
+         case EventConstants.WorldEntrySuccess:
+            handleEvent((WorldEntrySuccessEvent) wevent);
+            break;
+
+         default:
+            handleEvent(wevent);
+            break;
+      }
+   }
+
+   /**
+    * Called when the client recieves an event it doesn't recognize.
+    *
+    * @param wevent World Event
+    **/
+   public void handleEvent(WorldEvent wevent)
+   {
+      client.LoggingService.severe("CEH", "Unrecognized Event: " + wevent);
+   }
+
+   /**
+    * Called when the client recieves a WorldLoginSuccess event.
+    *
+    * @param event WorldLoginSuccess event
+    * @throws IllegalArgumentException
+    *         if <code>event</code> is <code>null</code>
+    **/
+   protected void handleEvent(WorldLoginSuccessEvent event)
+   {
+      if (event == null)
+      {
+         String msg = "event cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      // tell the client she's logged in
+      String worldName = event.WorldName;
+      client.output("Successfully logged into world " + worldName);
+   }
+
+   /**
+    * Called when the client recieves a WorldEntrySuccess event.
+    *
+    * @param event WorldEntrySuccess event
+    * @throws IllegalArgumentException
+    *         if <code>event</code> is <code>null</code>
+    **/
+   protected void handleEvent(WorldEntrySuccessEvent event)
+   {
+      if (event == null)
+      {
+         String msg = "event cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      // tell the client what room to enter
+      String worldName = event.WorldName;
+      int roomID = event.RoomID;
+      int doorID = event.DoorID;
+
+      client.output("Successfully entered world " + worldName + ". Please " +
+         "enter room " + roomID + " through door " + doorID + " within" +
+         " the next 120 seconds.");
+   }
+
+}
\ No newline at end of file
diff --git a/server/scs/jc/ClientState.java b/server/scs/jc/ClientState.java
new file mode 100644
index 0000000..3df3185
--- /dev/null
+++ b/server/scs/jc/ClientState.java
@@ -0,0 +1,19 @@
+package psl.chime4.server.scs.jc;
+
+/**
+ * This class stores pertinent information about the client.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public final class ClientState
+{
+   public String UniqueTopic;
+   public String Username;
+   public String Password;
+
+   public String EventServer;
+   public int EventServerPort;
+   /** topic of the world the client is currently logged into **/
+   public String WorldTopic;
+}
diff --git a/server/scs/jc/ConsoleLoggingService.java b/server/scs/jc/ConsoleLoggingService.java
new file mode 100644
index 0000000..21855db
--- /dev/null
+++ b/server/scs/jc/ConsoleLoggingService.java
@@ -0,0 +1,73 @@
+package psl.chime4.server.scs.jc;
+
+import psl.chime4.server.scs.service.*;
+import psl.chime4.server.scs.log.LoggingService;
+
+/**
+ * A simple implementation of the LoggingService that logs everything to the
+ * console.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class ConsoleLoggingService extends AbstractService
+   implements LoggingService
+{
+
+   /**
+    * Log a configuration message.
+    *
+    * @param cat category for the logging message
+    * @param msg logging message
+    */
+   public void config(String cat, String msg)
+   {
+      System.out.println("\nCONFIG:[" + cat + "]:" + msg);
+   }
+
+   /**
+    * Log an informational message.
+    *
+    * @param cat category for the logging message
+    * @param msg logging message
+    */
+   public void info(String cat, String msg)
+   {
+      System.out.println("\nINFO:[" + cat + "]:" + msg);
+   }
+
+   /**
+    * Log a severe warning.
+    *
+    * @param cat category for the logging service
+    * @param msg log message
+    */
+   public void severe(String cat, String msg)
+   {
+      System.out.println("\nSEVERE:[" + cat + "]:" + msg);
+   }
+
+   /**
+    * Log an exception generated during the runtime.
+    *
+    * @param cat   category for the logging message
+    * @param msg   log message
+    * @param cause cause of the log msg
+    */
+   public void throwing(String cat, String msg, Throwable cause)
+   {
+      System.out.println("\nTHROW:[" + cat + "]:" + msg + ":" + cause);
+   }
+
+   /**
+    * Log a warning message.
+    *
+    * @param cat category for the logging message
+    * @param msg log message
+    */
+   public void warning(String cat, String msg)
+   {
+      System.out.println("\nWARNING:[" + cat + "]:" + msg);
+   }
+
+}
\ No newline at end of file
diff --git a/server/scs/jc/NonAuthenticationService.java b/server/scs/jc/NonAuthenticationService.java
new file mode 100644
index 0000000..b610ac3
--- /dev/null
+++ b/server/scs/jc/NonAuthenticationService.java
@@ -0,0 +1,45 @@
+package psl.chime4.server.scs.jc;
+
+import psl.chime4.server.scs.auth.AuthenticationService;
+import psl.chime4.server.scs.service.*;
+
+/**
+ * A stupid implementation of the AuthenticationService that simply
+ * authenticates all users.
+ *
+ **/
+public class NonAuthenticationService extends AbstractService
+   implements AuthenticationService
+{
+
+   /**
+    * Authenticate a user with the given name and proof of identity.
+    *
+    * @param username name of the user
+    * @param ticket   proof that the user is who she says she is
+    * @return <code>null</code> if the user can logon else a String object
+    *        explaining why the user can logon
+    * @throws ServiceException
+    *        if the service fails
+    */
+   public String authenticate(String username, byte[] ticket)
+      throws ServiceException
+   {
+      return null;
+   }
+
+   /**
+    * Used when a client requests a new Authentication ticket.
+    *
+    * @param username name of the user
+    * @param ticket   an existing ticket that acts as proof
+    * @return <code>null</code> if the ticket is denied else
+    *         an array of bytes containing the new ticket for the user
+    * @throws ServiceException
+    *        if the service fails
+    */
+   public byte[] createTicket(String username, byte[] ticket) throws ServiceException
+   {
+      return null;
+   }
+}
\ No newline at end of file
diff --git a/server/scs/jc/SimplePersistenceService.java b/server/scs/jc/SimplePersistenceService.java
new file mode 100644
index 0000000..e85eee9
--- /dev/null
+++ b/server/scs/jc/SimplePersistenceService.java
@@ -0,0 +1,98 @@
+package psl.chime4.server.scs.jc;
+
+import psl.chime4.server.scs.service.*;
+import psl.chime4.server.scs.persist.*;
+
+import java.util.IdentityHashMap;
+
+/**
+ * A simple implementation of the persistence service that stores all
+ * objects in memory.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class SimplePersistenceService extends AbstractService
+   implements PersistenceService
+{
+   int objectID = 0;
+   private IdentityHashMap objects = new IdentityHashMap();
+
+   /**
+    * Construct a new PersistentObject of the given type.
+    *
+    * @param type the type of object to construct
+    * @return PersistentObject of the given type
+    * @throws IllegalArgumentException
+    *        if <code>type</code> is <code>null</code>
+    * @throws ServiceException
+    *        if something goes wrong
+    */
+   public PersistentObject create(Class type) throws ServiceException
+   {
+      // increment the objectID counter
+      objectID += 1;
+
+      try
+      {
+         // instantiate the class
+         PersistentObject pobj = (PersistentObject) type.newInstance();
+         ObjectID oid = new ObjectID(objectID, type);
+         pobj.setObjectID(oid);
+         pobj.setPersistenceID(objectID);
+         pobj.setPersistenceService(this);
+
+         // put it in the map
+         objects.put(oid, pobj);
+
+         return pobj;
+      }
+      catch (Exception e)
+      {
+         String msg = "couldn't create object of type: " + type;
+         throw new ServiceException(msg, e);
+      }
+   }
+
+   /**
+    * Delete the object with the given id from the persistent layer.
+    *
+    * @param id id of the object to delete
+    * @throws IllegalArgumentException
+    *        if <code>id</code> is <code>null</code>
+    * @throws ServiceException
+    *        if the request fails
+    */
+   public void delete(ObjectID id) throws ServiceException
+   {
+      objects.remove(id);
+   }
+
+   /**
+    * Load an object with the given id from the persistence layer.
+    *
+    * @param id object for the id
+    * @return PersistentObject mapped to <code>id</code>
+    * @throws IllegalArgumentException
+    *        if <code>id</code> is <code>null</code>
+    * @throws ServiceException
+    *        if the request fails
+    */
+   public PersistentObject load(ObjectID id) throws ServiceException
+   {
+      return (PersistentObject) objects.get(id);
+   }
+
+   /**
+    * Store an object in the persistence service.
+    *
+    * @param pobj PersistentObject to write to the persistence layer
+    * @throws ServiceException
+    *        if the request fails
+    */
+   public void store(PersistentObject pobj) throws ServiceException
+   {
+      objects.put(pobj.getObjectID(), pobj);
+   }
+
+}
\ No newline at end of file
diff --git a/server/scs/jc/command/Command.java b/server/scs/jc/command/Command.java
new file mode 100644
index 0000000..cea6193
--- /dev/null
+++ b/server/scs/jc/command/Command.java
@@ -0,0 +1,23 @@
+package psl.chime4.server.scs.jc.command;
+
+import psl.chime4.server.scs.jc.*;
+
+/**
+ * Basic interface for all commands that can be executed by the client.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public abstract class Command
+{
+   /**
+    * Tell the command to execute its function.
+    *
+    * @param client client that executed the command
+    * @param input  what the client typed
+    * @throws Exception
+    *         if the command cannot be executed
+    **/
+   public abstract void execute(Client client, String input) throws Exception;
+}
+
diff --git a/server/scs/jc/command/QuitCommand.java b/server/scs/jc/command/QuitCommand.java
new file mode 100644
index 0000000..9ea247a
--- /dev/null
+++ b/server/scs/jc/command/QuitCommand.java
@@ -0,0 +1,18 @@
+package psl.chime4.server.scs.jc.command;
+
+import psl.chime4.server.scs.jc.*;
+
+/**
+ * Command to quit the client.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class QuitCommand extends Command
+{
+   public void execute(Client client, String input) throws Exception
+   {
+      client.output("Shutting down client...");
+      System.exit(0);
+   }
+}
\ No newline at end of file
diff --git a/server/scs/jc/command/WorldEntryCommand.java b/server/scs/jc/command/WorldEntryCommand.java
new file mode 100644
index 0000000..b73f836
--- /dev/null
+++ b/server/scs/jc/command/WorldEntryCommand.java
@@ -0,0 +1,42 @@
+package psl.chime4.server.scs.jc.command;
+
+import psl.chime4.server.scs.*;
+import psl.chime4.server.scs.jc.*;
+import psl.chime4.server.scs.ws.event.*;
+import psl.chime4.server.ces.*;
+
+/**
+ * Tells the client to enter a given world. The syntax is:
+ *
+ * enter_world: <worldTopic>
+ *
+ * Sends a WorldEntryEvent to the world server.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class WorldEntryCommand extends Command
+{
+
+   /**
+    * Tell the command to execute its function.
+    *
+    * @param client client that executed the command
+    * @param input  what the client typed
+    * @throws Exception
+    *        if the command cannot be executed
+    */
+   public void execute(Client client, String input) throws Exception
+   {
+      // get the world topic to publish to
+      ClientState state = client.getState();
+
+      WorldEvent worldEntry = new WorldEntryEvent(state.Username);
+      Event event = client.EventService.createEmptyEvent();
+      event = worldEntry.toCesEvent(event);
+
+      client.EventService.publish(state.EventServer, state.EventServerPort,
+                                  state.WorldTopic, event);
+   }
+
+}
\ No newline at end of file
diff --git a/server/scs/jc/command/WorldLoginCommand.java b/server/scs/jc/command/WorldLoginCommand.java
new file mode 100644
index 0000000..08beb18
--- /dev/null
+++ b/server/scs/jc/command/WorldLoginCommand.java
@@ -0,0 +1,58 @@
+package psl.chime4.server.scs.jc.command;
+
+import psl.chime4.server.ces.*;
+import psl.chime4.server.scs.jc.*;
+import psl.chime4.server.scs.ws.event.*;
+import psl.chime4.server.scs.*;
+
+import java.util.*;
+
+/**
+ * Used by the client to login into the world. It's of the form:
+ *
+ * login: {server} {port} {world uniqueTopic} {username} {pass}
+ *
+ * This command will then send a WorldLoginEvent to the world.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class WorldLoginCommand extends Command
+{
+   public void execute(Client client, String input) throws Exception
+   {
+      // parse out the arguments
+      StringTokenizer tokenizer = new StringTokenizer(input);
+      String eServer = tokenizer.nextToken();
+      int eServerPort = Integer.parseInt(tokenizer.nextToken());
+      String worldTopic = tokenizer.nextToken();
+      String username = tokenizer.nextToken();
+      String pass = tokenizer.nextToken();
+
+      // set up the client's state
+      ClientState state = client.getState();
+      state.EventServer = eServer;
+      state.EventServerPort = eServerPort;
+      state.Username = username;
+      state.Password = pass;
+      state.UniqueTopic = "topic-" + username;
+      state.WorldTopic = worldTopic;
+
+      // make the world login event
+      WorldEvent loginEvent = new WorldLoginEvent(
+         username, pass.getBytes(), state.UniqueTopic);
+      Event event = client.EventService.createEmptyEvent();
+      event = loginEvent.toCesEvent(event);
+
+      // open a connection to the event server
+      client.EventService.openConnection(eServer, eServerPort);
+
+      // register the client's event handler
+      client.EventService.registerEventHandler(
+         eServer, eServerPort, state.UniqueTopic, client.EventHandler);
+
+      // send the login event
+      client.EventService.publish(eServer, eServerPort, worldTopic,
+                                  event);
+   }
+}
\ No newline at end of file
diff --git a/server/scs/log/LoggingService.java b/server/scs/log/LoggingService.java
new file mode 100644
index 0000000..5f188b5
--- /dev/null
+++ b/server/scs/log/LoggingService.java
@@ -0,0 +1,54 @@
+package psl.chime4.server.scs.log;
+
+import psl.chime4.server.scs.service.*;
+
+/**
+ * Defines an object that is capable of logging messages to some persistent
+ * medium.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public interface LoggingService extends Service
+{
+   /**
+    * Log a configuration message.
+    *
+    * @param cat category for the logging message
+    * @param msg logging message
+    **/
+   public void config(String cat, String msg);
+
+   /**
+    * Log an informational message.
+    *
+    * @param cat category for the logging message
+    * @param msg logging message
+    **/
+   public void info(String cat, String msg);
+
+   /**
+    * Log a warning message.
+    *
+    * @param cat category for the logging message
+    * @param msg log message
+    **/
+   public void warning(String cat, String msg);
+
+   /**
+    * Log an exception generated during the runtime.
+    *
+    * @param cat   category for the logging message
+    * @param msg   log message
+    * @param cause exception thrown
+    **/
+   public void throwing(String cat, String msg, Throwable cause);
+
+   /**
+    * Log a severe warning.
+    *
+    * @param cat category for the logging service
+    * @param msg log message
+    **/
+   public void severe(String cat, String msg);
+}
\ No newline at end of file
diff --git a/server/scs/metadata/Metadata.java b/server/scs/metadata/Metadata.java
new file mode 100644
index 0000000..e445e8b
--- /dev/null
+++ b/server/scs/metadata/Metadata.java
@@ -0,0 +1,78 @@
+package psl.chime4.server.scs.metadata;
+
+import psl.chime4.server.data.metadata.ResourceDescriptor;
+import psl.chime4.server.scs.persist.*;
+
+/**
+ * Represents a piece of metadata in the world.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public final class Metadata extends PersistentObject
+{
+   private boolean evaluated;
+   private String url;
+   private ResourceDescriptor resDes;
+
+   /**
+    * Get the underlying resource descriptor.
+    *
+    * @return underlying resource descriptor
+    **/
+   public ResourceDescriptor getResourceDescriptor()
+   {
+      return resDes;
+   }
+
+   /**
+    * Set the underlying resource descriptor.
+    *
+    * @param resDes the underlying resource descriptor
+    **/
+   public void setResourceDescriptor(ResourceDescriptor resDes)
+   {
+      this.resDes = resDes;
+   }
+
+   /**
+    * Get the URL this metadata describes.
+    *
+    * @return url for the resource this metadata describes
+    **/
+   public String getURL()
+   {
+      return url;
+   }
+
+   /**
+    * Set the URL this metadata describes.
+    *
+    * @param url metadata this metadata describes
+    **/
+   public void setURL(String url)
+   {
+      this.url = url;
+   }
+
+   /**
+    * Get whether this metadata has been completed evaluated.
+    *
+    * @return <code>true</code> if the metadata has been evaluated, else
+    *         <code>false</code>
+    **/
+   public boolean isEvaluated()
+   {
+      return evaluated;
+   }
+
+   /**
+    * Set whether this metadata has been completely evaluated.
+    *
+    * @param evaluated evaluation status of this metadata
+    **/
+   public void setEvaluated(boolean evaluated)
+   {
+      this.evaluated = evaluated;
+   }
+}
\ No newline at end of file
diff --git a/server/scs/metadata/MetadataService.java b/server/scs/metadata/MetadataService.java
new file mode 100644
index 0000000..340478c
--- /dev/null
+++ b/server/scs/metadata/MetadataService.java
@@ -0,0 +1,22 @@
+package psl.chime4.server.scs.metadata;
+
+import psl.chime4.server.scs.service.*;
+
+/**
+ * A MetadataService is capable of retrieving metadata about resources.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public interface MetadataService extends Service
+{
+   /**
+    * Evaluate a Metadata by retrieving as much metadata as possible about the
+    * url defined by the Metadata.
+    *
+    * @param mdata Metadata to evaluate
+    * @throws ServiceException
+    *         if something goes wrong
+    **/
+   public void evaluate(Metadata mdata) throws ServiceException;
+}
\ No newline at end of file
diff --git a/server/scs/persist/ObjectID.java b/server/scs/persist/ObjectID.java
new file mode 100644
index 0000000..f4be60a
--- /dev/null
+++ b/server/scs/persist/ObjectID.java
@@ -0,0 +1,54 @@
+package psl.chime4.server.scs.persist;
+
+
+/**
+ * An ObjectID unique identifies an object to the persistence service.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public final class ObjectID
+{
+   private int objID;
+   private Class ownerType;
+
+   /**
+    * Construct a new ObjectID with the given id and owner type.
+    *
+    * @param objID id for the new object
+    * @param type  the type of the new object
+    * @throws IllegalArgumentException
+    *         if <code>type</code> is <code>null</code>
+    **/
+   public ObjectID(int objID, Class type)
+   {
+      if (type == null)
+      {
+         String msg = "no parameter can be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      this.objID = objID;
+      this.ownerType = type;
+   }
+
+   /**
+    * Get the unique integer id for this object id.
+    *
+    * @return unique integer id for this object id
+    **/
+   public int getID()
+   {
+      return objID;
+   }
+
+   /**
+    * Get the type of the owner for this object id.
+    *
+    * @return type of the owner for this object
+    **/
+   public Class getOwnerType()
+   {
+      return ownerType;
+   }
+}
\ No newline at end of file
diff --git a/server/scs/persist/PersistenceService.java b/server/scs/persist/PersistenceService.java
new file mode 100644
index 0000000..43001e5
--- /dev/null
+++ b/server/scs/persist/PersistenceService.java
@@ -0,0 +1,59 @@
+package psl.chime4.server.scs.persist;
+
+import psl.chime4.server.scs.service.*;
+
+/**
+ * The PersistenceService is responsible for the creation and storage of all
+ * objects on the server. It is the primary interface to the persistence
+ * layer.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public interface PersistenceService extends Service
+{
+   /**
+    * Construct a new PersistentObject of the given type.
+    *
+    * @param type the type of object to construct
+    * @return PersistentObject of the given type
+    * @throws IllegalArgumentException
+    *         if <code>type</code> is <code>null</code>
+    * @throws ServiceException
+    *         if something goes wrong
+    **/
+   public PersistentObject create(Class type) throws ServiceException;
+
+   /**
+    * Load an object with the given id from the persistence layer.
+    *
+    * @param id object for the id
+    * @return PersistentObject mapped to <code>id</code>
+    * @throws IllegalArgumentException
+    *         if <code>id</code> is <code>null</code>
+    * @throws ServiceException
+    *         if the request fails
+    **/
+   public PersistentObject load(ObjectID id) throws ServiceException;
+
+   /**
+    * Store an object in the persistence service.
+    *
+    * @param pobj PersistentObject to write to the persistence layer
+    * @throws ServiceException
+    *         if the request fails
+    **/
+   public void store(PersistentObject pobj) throws ServiceException;
+
+   /**
+    * Delete the object with the given id from the persistent layer.
+    *
+    * @param id id of the object to delete
+    * @throws IllegalArgumentException
+    *         if <code>id</code> is <code>null</code>
+    * @throws ServiceException
+    *         if the request fails
+    **/
+   public void delete(ObjectID id) throws ServiceException;
+}
+
diff --git a/server/scs/persist/PersistentObject.java b/server/scs/persist/PersistentObject.java
new file mode 100644
index 0000000..7dcf0c5
--- /dev/null
+++ b/server/scs/persist/PersistentObject.java
@@ -0,0 +1,122 @@
+package psl.chime4.server.scs.persist;
+
+import psl.chime4.server.data.Persistent;
+
+/**
+ * An object that is capable of being persisted to the persistence layer.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public abstract class PersistentObject implements Persistent
+{
+   private int persistenceID;
+   private ObjectID oid;
+   private PersistenceService perService;
+
+   /**
+    * Get the persistence id of the object.
+    *
+    * @return persistence id
+    **/
+   public int getPersistenceID()
+   {
+      return persistenceID;
+   }
+
+   /**
+    * Set the persistence id of the object.
+    *
+    * @param persistenceID new persistence id of the object
+    **/
+   public void setPersistenceID(int persistenceID)
+   {
+      this.persistenceID = persistenceID;
+   }
+
+   /**
+    * Get the object id for this object.
+    *
+    * @return ObjectID for this object
+    **/
+   public ObjectID getObjectID()
+   {
+      return oid;
+   }
+
+   /**
+    * Set the object id for this object.
+    *
+    * @param oid ObjectID for this object
+    **/
+   public void setObjectID(ObjectID oid)
+   {
+      this.oid = oid;
+   }
+
+   /**
+    * Get the persistence service that created this persistent object.
+    *
+    * @return persistence service that created this object
+    **/
+   public PersistenceService getPersistenceService()
+   {
+      return perService;
+   }
+
+   /**
+    * Set the persistence service for this object.
+    *
+    * @param pService PersistenceService that created this object
+    **/
+   public void setPersistenceService(PersistenceService pService)
+   {
+      this.perService = pService;
+   }
+
+   /**
+    * The PersistenceService must call this method immediately after an
+    * object has been created.
+    *
+    * @param pService PersistenceService that created the object
+    **/
+   public void onCreate(PersistenceService pService)
+   {
+      ; // do nothing
+   }
+
+   /**
+    * The PersistenceService must call this method immediately after an
+    * object has been loaded back from the persistence layer.
+    *
+    * @param pService PersistenceService that loaded the object
+    **/
+   public void onLoad(PersistenceService pService)
+   {
+      ; // do nothing
+   }
+
+   /**
+    * The PersistenceService must call this method immediately before an
+    * object is stored in the persistence layer.
+    *
+    * @param pService PersistenceService that is storing the object
+    **/
+   public void onStore(PersistenceService pService)
+   {
+      ; // do nothing
+   }
+
+   /**
+    * The PersistenceService must call this method immediately before an
+    * object is deleted from the persistence layer.
+    *
+    * @param pService PersistenceService deleting the object
+    **/
+   public void onDelete(PersistenceService pService)
+   {
+      ; // do nothing
+   }
+}
+
+
diff --git a/server/scs/service/AbstractService.java b/server/scs/service/AbstractService.java
new file mode 100644
index 0000000..38bcfe2
--- /dev/null
+++ b/server/scs/service/AbstractService.java
@@ -0,0 +1,78 @@
+package psl.chime4.server.scs.service;
+
+/**
+ * A default, simple implementation for the Service interface.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public abstract class AbstractService implements Service
+{
+   private ServiceContext context;
+   private String serviceName;
+
+   public ServiceContext getServiceContext()
+   {
+      return context;
+   }
+
+   public void setServiceContext(ServiceContext context)
+   {
+      this.context = context;
+   }
+
+   /**
+    * Initialize the Service. At this point the Service has not started.
+    *
+    * @param params parameters passed from server.xml
+    * @throws ServiceException
+    *        if the service cannot initialize itself
+    */
+   public void initialize(ServiceParamMap params) throws ServiceException
+   {
+   }
+
+   /**
+    * Start the Service. At this point the service is running.
+    *
+    * @throws ServiceException
+    *         if the service cannot start for some reason
+    **/
+   public void start() throws ServiceException
+   {
+   }
+
+   /**
+    * Shut the Service down. The Service has roughly two minutes to shutdown
+    * before it will be forcefully shutdown.
+    **/
+   public void stop()
+   {
+   }
+
+   /**
+    * Get the name of the server. This is unique in the service context.
+    *
+    * @return name of the service
+    */
+   public String getServiceName()
+   {
+      return serviceName;
+   }
+
+   /**
+    * Set the name of the server. This should be unique in the entire service
+    * context.
+    *
+    * @param name name of the service
+    */
+   public void setServiceName(String name)
+   {
+      this.serviceName = name;
+   }
+
+   public String toString()
+   {
+      return getClass().toString() + "[name=" + serviceName + "]";
+   }
+}
\ No newline at end of file
diff --git a/server/scs/service/Service.java b/server/scs/service/Service.java
new file mode 100644
index 0000000..3a1651b
--- /dev/null
+++ b/server/scs/service/Service.java
@@ -0,0 +1,62 @@
+package psl.chime4.server.scs.service;
+
+/**
+ * Represents a Service offered by the Chime Server.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public interface Service
+{
+   /**
+    * Initialize the Service. At this point the Service has not started.
+    *
+    * @param params parameters passed from server.xml
+    * @throws ServiceException
+    *         if the service cannot initialize itself
+    **/
+   public void initialize(ServiceParamMap params) throws ServiceException;
+
+   /**
+    * Start the Service. At this point the service is running.
+    *
+    * @throws ServiceException
+    *         if the service cannot start for some reason
+    **/
+   public void start() throws ServiceException;
+
+   /**
+    * Shut the Service down. The Service has roughly two minutes to shutdown
+    * before it will be forcefully shutdown.
+    **/
+   public void stop();
+
+   /**
+    * Get the ServiceContext that is managing this service.
+    *
+    * @return ServiceContext for this service
+    **/
+   public ServiceContext getServiceContext();
+
+   /**
+    * Set the ServiceContext that is managing this service.
+    *
+    * @param context ServiceContext for this service
+    **/
+   public void setServiceContext(ServiceContext context);
+
+   /**
+    * Get the name of the server. This is unique in the service context.
+    *
+    * @return name of the service
+    **/
+   public String getServiceName();
+
+   /**
+    * Set the name of the server. This should be unique in the entire service
+    * context.
+    *
+    * @param name name of the service
+    **/
+   public void setServiceName(String name);
+}
\ No newline at end of file
diff --git a/server/scs/service/ServiceContext.java b/server/scs/service/ServiceContext.java
new file mode 100644
index 0000000..ea9ce6b
--- /dev/null
+++ b/server/scs/service/ServiceContext.java
@@ -0,0 +1,160 @@
+package psl.chime4.server.scs.service;
+
+import java.util.*;
+import java.io.*;
+
+import org.jdom.*;
+import org.jdom.input.*;
+
+/**
+ * A collection of services that define a server.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class ServiceContext
+{
+   Map serviceMap = new HashMap();
+
+   /**
+    * Place a Service in the context under a given name.
+    *
+    * @param name the name of the service
+    * @return Service located under <code>name</code> or <code>null</code>
+    * @throws IllegalArgumentException
+    *         if <code>name</code> is <code>null</code>
+    **/
+   public Service getService(String name)
+   {
+      if (name == null)
+      {
+         String msg = "name cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      synchronized(serviceMap)
+      {
+         return (Service) serviceMap.get(name);
+      }
+   }
+
+   /**
+    * Put a Service in the context. It will be available to all other
+    * services.
+    *
+    * @param name    name to place the Service under
+    * @param service the service to place in the context
+    * @throws IllegalArgumentException
+    *         if any parameter is <code>null</code> or if a service is
+    *         already registered under that exception
+    **/
+   public void putService(String name, Service service)
+   {
+      if ((name == null) || (service == null))
+      {
+         String msg = "no param can be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      if (serviceMap.containsKey(name))
+      {
+         String msg = "service already registered under name: " + name;
+         throw new IllegalArgumentException(msg);
+      }
+
+      synchronized(serviceMap)
+      {
+         serviceMap.put(name, service);
+      }
+   }
+
+   /**
+    * Initialized the ServiceContext from a given server.xml file.
+    *
+    * @param in InputStream containing XML data to configure the server
+    * @throws IllegalArguemntException
+    *         if <code>in</code> is <code>null</code>
+    * @throws ServiceException
+    *         if the server.xml contains bad data
+    **/
+   public void initialize(InputStream in) throws ServiceException
+   {
+      try
+      {
+         SAXBuilder builder = new SAXBuilder();
+         Document doc = builder.build(in);
+         Element root = doc.getRootElement();
+         in.close();
+
+         // get all of the children named 'service', instantiate the classes
+         // and then put them in the map
+         List serviceList = root.getChildren("service");
+         for (Iterator it = serviceList.iterator(); it.hasNext(); )
+         {
+            Element serviceNode = (Element) it.next();
+            String serviceName = serviceNode.getAttributeValue("name");
+            String serviceClass = serviceNode.getAttributeValue("class");
+            Service service =
+               (Service) Class.forName(serviceClass).newInstance();
+
+            // put it in the service map and set the context
+            service.setServiceContext(this);
+            service.setServiceName(serviceName);
+            serviceMap.put(serviceName, service);
+         }
+
+         // now go through and do the parameters of each one
+         ServiceParamMap serviceParamMap = new ServiceParamMap();
+
+         for (Iterator it = serviceList.iterator(); it.hasNext(); )
+         {
+            Element serviceNode = (Element) it.next();
+            String serviceName = serviceNode.getAttributeValue("name");
+            Service currentService = getService(serviceName);
+
+            // get all the parameters
+            serviceParamMap.clear();
+            List paramList = serviceNode.getChildren("param");
+            for (Iterator pit = paramList.iterator(); pit.hasNext();)
+            {
+               Element paramNode = (Element) pit.next();
+               String paramName = paramNode.getAttributeValue("name");
+               String paramType = paramNode.getAttributeValue("type");
+               String paramVal = paramNode.getAttributeValue("value");
+
+               // figure out the name, value, and put it in the map
+               ServiceParam param = new ServiceParam();
+               param.setName(paramName);
+
+               if (paramType.equals("string"))
+               {
+                  param.setValue(paramVal);
+               } else if (paramType.equals("integer"))
+               {
+                  param.setValue(Integer.valueOf(paramVal));
+               } else if (paramType.equals("service"))
+               {
+                  // if it's another service then the value is name of that
+                  // service
+                  param.setValue(getService(paramVal));
+               } else
+               {
+                  String msg = "unknown param value type";
+                  throw new ServiceException(msg);
+               }
+
+               serviceParamMap.addParam(paramName, param);
+            }
+
+            // now initialize the service
+            currentService.initialize(serviceParamMap);
+         }
+      }
+      catch (Exception e)
+      {
+         String msg = "couldn't initialize service context";
+         throw new ServiceException(msg, e);
+      }
+   }
+}
+
diff --git a/server/scs/service/ServiceException.java b/server/scs/service/ServiceException.java
new file mode 100644
index 0000000..c317b2a
--- /dev/null
+++ b/server/scs/service/ServiceException.java
@@ -0,0 +1,30 @@
+package psl.chime4.server.scs.service;
+
+/**
+ * A generic exception in the Service framework.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class ServiceException extends Exception
+{
+   public ServiceException()
+   {
+      super();
+   }
+
+   public ServiceException(String msg)
+   {
+      super(msg);
+   }
+
+   public ServiceException(String msg, Throwable cause)
+   {
+      super(msg, cause);
+   }
+
+   public ServiceException(Throwable cause)
+   {
+      super(cause);
+   }
+}
\ No newline at end of file
diff --git a/server/scs/service/ServiceParam.java b/server/scs/service/ServiceParam.java
new file mode 100644
index 0000000..d962d86
--- /dev/null
+++ b/server/scs/service/ServiceParam.java
@@ -0,0 +1,95 @@
+package psl.chime4.server.scs.service;
+
+/**
+ * A parameter which can be passed to configure a Service.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public final class ServiceParam
+{
+   private String name;
+   private Object value;
+
+   /**
+    * Get the name of the parameter.
+    *
+    * @return name of the parameter
+    **/
+   public String getName()
+   {
+      return name;
+   }
+
+   /**
+    * Set the name of the parameter.
+    *
+    * @param name name of the parameter
+    **/
+   public void setName(String name)
+   {
+      this.name = name;
+   }
+
+   /**
+    * Get the value of the parameter.
+    *
+    * @return value of the parameter
+    **/
+   public Object getValue()
+   {
+      return value;
+   }
+
+   /**
+    * Set the value of the parameter.
+    *
+    * @param value value of the parameter
+    **/
+   public void setValue(Object value)
+   {
+      this.value = value;
+   }
+
+   /**
+    * Get the type of the value.
+    *
+    * @return type of the value or <code>null</code> if there is no value
+    **/
+   public Class getType()
+   {
+      if (value != null)
+      {
+         return value.getClass();
+      } else
+      {
+         return null;
+      }
+   }
+
+   /**
+    * Get the value of the parameter as a string.
+    *
+    * @return value of the parameter as a string
+    **/
+   public String getValueAsString()
+   {
+      return (String) value;
+   }
+
+   /**
+    * Get the value of the parameter as an integer.
+    *
+    * @return value of the parameter as an integer
+    **/
+   public int getValueAsInt()
+   {
+      return ((Integer) value).intValue();
+   }
+
+   public String toString()
+   {
+      return "ServiceParam[name=" + name + ", value=" + value + ", type=" +
+         getType() + "]";
+   }
+}
\ No newline at end of file
diff --git a/server/scs/service/ServiceParamMap.java b/server/scs/service/ServiceParamMap.java
new file mode 100644
index 0000000..9a70854
--- /dev/null
+++ b/server/scs/service/ServiceParamMap.java
@@ -0,0 +1,69 @@
+package psl.chime4.server.scs.service;
+
+import java.util.*;
+
+/**
+ * A collection of parameters which might be passed to a service in order to
+ * initialize it.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public final class ServiceParamMap
+{
+   private Map params = new HashMap();
+
+   /**
+    * Add a parameter to the map.
+    *
+    * @param name  the name of the parameter
+    * @param param the parameter to add to the map
+    * @throws IllegalArgumentException
+    *         if any parameter is <code>null</code>
+    **/
+   public void addParam(String name, ServiceParam param)
+   {
+      if ((name == null) || (param == null))
+      {
+         String msg = "no parameter can be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      params.put(name, param);
+   }
+
+   /**
+    * Get a parameter from the map.
+    *
+    * @param name the name of the parameter
+    * @return ServiceParam mapped to <code>name</code> or <code>null</code>
+    * @throws NoSuchElementException
+    *         if no parameter exists with <code>name</code>
+    * @throws IllegalArgumentException
+    *         if <code>name</code> is <code>null</code>
+    **/
+   public ServiceParam getParam(String name)
+   {
+      if (!params.containsKey(name))
+      {
+         String msg = "no such parameter: " + name;
+         throw new NoSuchElementException(msg);
+      }
+
+      return (ServiceParam) params.get(name);
+   }
+
+   /**
+    * Erase all parameters in the map. The map can be reused after this call
+    * is made.
+    **/
+   public void clear()
+   {
+      params.clear();
+   }
+
+   public String toString()
+   {
+      return "ServiceParamMap[params=" + params + "]";
+   }
+}
\ No newline at end of file
diff --git a/server/scs/service/StartServer.java b/server/scs/service/StartServer.java
new file mode 100644
index 0000000..8f69835
--- /dev/null
+++ b/server/scs/service/StartServer.java
@@ -0,0 +1,22 @@
+package psl.chime4.server.scs.service;
+
+import java.io.*;
+
+/**
+ * Start the server process.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class StartServer
+{
+   public static void main(String[] args) throws Exception
+   {
+      String filename = args[0];
+      FileInputStream in = new FileInputStream(filename);
+
+      ServiceContext context = new ServiceContext();
+      context.initialize(in);
+   }
+}
+
diff --git a/server/scs/ws/UserInfo.java b/server/scs/ws/UserInfo.java
new file mode 100644
index 0000000..6ff17a0
--- /dev/null
+++ b/server/scs/ws/UserInfo.java
@@ -0,0 +1,165 @@
+package psl.chime4.server.scs.ws;
+
+import psl.chime4.server.scs.persist.PersistentObject;
+import psl.chime4.server.scs.ws.view.Theme;
+
+import psl.chime4.server.ces.*;
+
+/**
+ * Represents information about a User logged onto the Chime server.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class UserInfo extends PersistentObject
+{
+   /** authentication status for the user **/
+   public boolean authenticated;
+
+   /** globally unique for this user **/
+   public String username;
+
+   /** the topic on the event server that only the user is listening to **/
+   public String uniqueTopic;
+
+   /** the current theme of the user **/
+   private Theme currentTheme;
+
+   /** EventBridge used to send events to the user **/
+   private EventBridge bridge;
+
+   /**
+    * Get whether this user has been authenticated.
+    *
+    * @return <code>true</code> if this user is authenticated else
+    *         <code>false</code>
+    **/
+   public boolean isAuthenticated()
+   {
+      return authenticated;
+   }
+
+   /**
+    * Set whether this user has been authenticated.
+    *
+    * @param authenticated the auth status of this user
+    **/
+   public void setAuthenticated(boolean authenticated)
+   {
+      this.authenticated = authenticated;
+   }
+
+   /**
+    * Get the globally unique username of this user.
+    *
+    * @return globally unique username of this user
+    **/
+   public String getUserName()
+   {
+      return username;
+   }
+
+   /**
+    * Set the globally unique username of this user.
+    *
+    * @param username username for this user
+    **/
+   public void setUserName(String username)
+   {
+      this.username = username;
+   }
+
+   /**
+    * Get the unique topic for this user. The user should be the only person
+    * subscribed to this topic.
+    *
+    * @return unique topic for this user
+    **/
+   public String getUniqueTopic()
+   {
+      return uniqueTopic;
+   }
+
+   /**
+    * Set the unique topic for this user.
+    *
+    * @param uniqueTopic unique topic for this user
+    **/
+   public void setUniqueTopic(String uniqueTopic)
+   {
+      this.uniqueTopic = uniqueTopic;
+   }
+
+   /**
+    * Get the current theme for this user.
+    *
+    * @return current theme for this user
+    **/
+   public Theme getCurrentTheme()
+   {
+      return currentTheme;
+   }
+
+   /**
+    * Set the current theme for this user.
+    *
+    * @param theme the current theme for this user
+    **/
+   public void setCurrentTheme(Theme theme)
+   {
+      this.currentTheme = theme;
+   }
+
+   /**
+    * Set the event bridge that will be used to send and recieve events
+    * directly to this user.
+    *
+    * @param bridge EventBridge used to send events to this user
+    * @throws IllegalArgumentException
+    *         if <code>bridge</code> is <code>null</code>
+    **/
+   public void setEventBridge(EventBridge bridge)
+   {
+      if (bridge == null)
+      {
+         String msg = "bridge cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      this.bridge = bridge;
+   }
+
+   /**
+    * Send an event to the unique topic of this user. Ideally, only the user
+    * will see this event.
+    *
+    * @param event    Event to send to the user
+    * @throws IllegalArgumentException
+    *         if any parameter is <code>null</code>
+    * @throws EventServiceException
+    *         if the event could not be sent
+    **/
+   public void sendEvent(Event event) throws EventServiceException
+   {
+      if (event == null)
+      {
+         String msg = "event cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      // publish the event to the user's unique topic
+      bridge.publish(event, uniqueTopic);
+   }
+
+   /**
+    * Get string representation suitable for debugging.
+    *
+    * @return debugging string
+    **/
+   public String toString()
+   {
+      return "UserInfo[authenticated=" + authenticated + ",username=" +
+         username + ",uniqueTopic=" + uniqueTopic + ",theme=" + currentTheme
+         + "]";
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/UserInfoService.java b/server/scs/ws/UserInfoService.java
new file mode 100644
index 0000000..83229e6
--- /dev/null
+++ b/server/scs/ws/UserInfoService.java
@@ -0,0 +1,152 @@
+package psl.chime4.server.scs.ws;
+
+import psl.chime4.server.scs.persist.*;
+import psl.chime4.server.scs.service.*;
+
+import java.util.*;
+
+/**
+ * Keeps track of all users logged into the current world service.
+ *
+ * @note Currently this class is not a true service. In the future this will
+ *       probably change.
+ * @note In the future this class will implement a ping service; it will
+ *       randomly ping users to determine if they're still connected and if
+ *       not it'll disconnect them
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class UserInfoService
+{
+   /** map used to store users **/
+   private Map userMap = new HashMap();
+
+   /** persistence service used to create UserInfo objects **/
+   private PersistenceService pService;
+
+   /** world service this object is working for **/
+   private WorldService wService;
+
+   /**
+    * Set the WorldService that this UserInfoService is working for.
+    *
+    * @param wService WorldService that this user info service is working for
+    * @throws IllegalArgumentException
+    *         if <code>wService</code> is <code>null</code>
+    **/
+   public void setWorldService(WorldService wService)
+   {
+      if (wService == null)
+      {
+         String msg = "wService cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      this.wService = wService;
+   }
+
+   /**
+    * Set the PersistenceService that this UserInfoService should use to
+    * create, delete, and store UserInfo objects.
+    *
+    * @param pService PersistenceService to use
+    * @throws IllegalArgumentException
+    *         if <code>pService</code> is <code>null</code>
+    **/
+   public void setPersistenceService(PersistenceService pService)
+   {
+      if (pService == null)
+      {
+         String msg = "pService cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      this.pService = pService;
+   }
+
+   /**
+    * Create a new User.
+    *
+    * @param name  globally unique name of the user
+    * @param topic unique topic for the user
+    * @return new UserInfo object initialized with a username and topic
+    * @throws IllegalArgumentException
+    *         if any parameter is <code>null</code>
+    * @throws ServiceException
+    *         if the underlying persistence service fails
+    **/
+   public UserInfo newUser(String name, String topic)
+   {
+      if ((name == null) || (topic == null))
+      {
+         String msg = "no parameter can be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      // create and initialize the user object
+      try
+      {
+         UserInfo newUser = (UserInfo) pService.create(UserInfo.class);
+
+         newUser.setUserName(name);
+         newUser.setUniqueTopic(topic);
+
+         // store it in the map
+         userMap.put(name, newUser);
+
+         return newUser;
+      }
+      catch (ServiceException se)
+      {
+         return null;
+         // persistence service has failed, do something
+      }
+   }
+
+   /**
+    * Return true if a user is currently logged in and authenticated.
+    *
+    * @param name name of the user
+    * @return <code>true</code> if user with the given name is authenticated
+    *         else <code>false</code>
+    * @throws IllegalArgumentException
+    *         if <code>name</code> is <code>null</code>
+    **/
+   public boolean isAuthenticated(String name)
+   {
+      if (name == null)
+      {
+         String msg = "name cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      if (!userMap.containsKey(name))
+      {
+         return false;
+      } else
+      {
+         UserInfo user = (UserInfo) userMap.get(name);
+         return user.isAuthenticated();
+      }
+   }
+
+   /**
+    * Get the user associated with a given globally unqiue username.
+    *
+    * @param username name of the user
+    * @return UserInfo that represents that user or <code>null</code>
+    * @throws IllegalArgumentException
+    *         if <code>username</code> is <code>null</code>
+    **/
+   public UserInfo getUser(String username)
+   {
+      if (username == null)
+      {
+         String msg = "username cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      return (UserInfo) userMap.get(username);
+   }
+}
diff --git a/server/scs/ws/World.java b/server/scs/ws/World.java
new file mode 100644
index 0000000..2f13e69
--- /dev/null
+++ b/server/scs/ws/World.java
@@ -0,0 +1,194 @@
+package psl.chime4.server.scs.ws;
+
+import psl.chime4.server.scs.persist.*;
+import psl.chime4.server.scs.service.*;
+import psl.chime4.server.scs.ws.data.*;
+import psl.chime4.server.scs.ws.view.*;
+import psl.chime4.server.scs.ws.view.render.*;
+
+import java.util.*;
+
+/**
+ * This object defines the state of the world.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public final class World extends PersistentObject
+{
+   /** world service that runs this world **/
+   private WorldService wService;
+
+   /** persistence service the world needs to create objects **/
+   private PersistenceService pService;
+
+   /** special lobby room **/
+   private Room lobby;
+
+   /** special door that leads into the world **/
+   private Door worldDoor;
+
+   /** map all objects in the world to their instance id **/
+   public Map instanceMap = new HashMap();
+
+   /**
+    * Initializes the world. Creates the special lobby and world door.
+    **/
+   public void initialize() throws ServiceException
+   {
+      lobby = createLobbyRoom();
+   }
+   /**
+    * Retrieve an instance from the map.
+    *
+    * @param oid object id for the object
+    * @return WorldObject mapped to that object or <code>null</code>
+    * @throws IllegalArgumentException
+    *         if <code>oid</code> is <code>null</code>
+    **/
+   public WorldObject getWorldObject(ObjectID oid)
+   {
+      if (oid == null)
+      {
+         String msg = "oid cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      return (WorldObject) instanceMap.get(oid);
+   }
+
+   /**
+    * Put a WorldObject in the map mapped to its object id.
+    *
+    * @param wobj to put into the map
+    * @throws IllegalArgumentException
+    *         if <code>oid</code> is <code>null</code>
+    **/
+   public void putWorldObject(WorldObject wobj)
+   {
+      if (wobj == null)
+      {
+         String msg = "wobj cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      instanceMap.put(wobj.getObjectID(), wobj);
+   }
+
+   /**
+    * Set the WorldService that manages this object.
+    *
+    * @param wService WorldService that manages this object
+    * @throws IllegalArgumentException
+    *         if <code>wService</code> is <code>null</code>
+    **/
+   public void setWorldService(WorldService wService)
+   {
+      if (wService == null)
+      {
+         String msg = "wService cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      this.wService = wService;
+   }
+
+   /**
+    * Set the PersistenceService the World should use to create objects. This
+    * method must be called by the WorldService when the world is created.
+    *
+    * @param pService PersistenceService used to create objects
+    * @throws IllegalArgumentException
+    *         if <code>pService</code> is <code>null</code>
+    **/
+   public void setPersistenceService(PersistenceService pService)
+   {
+      if (pService == null)
+      {
+         String msg = "pService cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      this.pService = pService;
+   }
+
+   /**
+    * Get the special lobby room.
+    *
+    * @return Room representing the special lobby room
+    **/
+   public Room getLobbyRoom()
+   {
+      return lobby;
+   }
+
+   /**
+    * Get the special world door that leads into the lobby from remote
+    * servers.
+    *
+    * @return Door that leads into the lobby
+    **/
+   public Door getLobbyEntrance()
+   {
+      return worldDoor;
+   }
+
+   /**
+    * Create the lobby room. Set both the structure of the lobby room and the
+    * view of it.
+    **/
+   private Room createLobbyRoom() throws ServiceException
+   {
+      // create a new room
+      Room lobby = (Room) pService.create(Room.class);
+      putWorldObject(lobby);
+
+      // give it a cube geometry
+      CubeGeometry geom = (CubeGeometry) pService.create(CubeGeometry.class);
+      geom.setHeight(30);
+      geom.setLength(30);
+      geom.setWidth(30);
+
+      View lobbyView = (View) pService.create(View.class);
+      lobbyView.setGeometry(geom);
+
+      // tell it to draw a basic black room
+      RenderInstruction ri = (RenderInstruction)
+         pService.create(RenderGeometryInstruction.class);
+      lobbyView.setRenderInstruction(ri);
+
+      // map the view of the lobby in the theme
+      wService.defaultTheme.putViewMapping(lobby, lobbyView);
+
+      // now place a door in the room
+      Door worldDoor = (Door) pService.create(Door.class);
+      this.worldDoor = worldDoor;
+      // say that the door leads to the lobby
+      worldDoor.setDestination(lobby);
+
+      // give it a cube geometry
+      CubeGeometry doorGeom = (CubeGeometry)
+         pService.create(CubeGeometry.class);
+      doorGeom.setHeight(10);
+      doorGeom.setLength(.5f);
+      doorGeom.setWidth(1.5f);
+
+      LocatedView doorView = (LocatedView) pService.create(LocatedView.class);
+      doorView.setGeometry(doorGeom);
+      doorView.setX(15);
+      doorView.setY(0);
+      doorView.setZ(0);
+
+      // map the view of the door to the door in the theme
+      wService.defaultTheme.putViewMapping(worldDoor, doorView);
+
+      RenderInstruction doorRI = (RenderInstruction)
+         pService.create(RenderGeometryInstruction.class);
+      doorView.setRenderInstruction(doorRI);
+
+      // add it to the lobby room
+      lobby.addDoor(worldDoor);
+
+      return lobby;
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/WorldService.java b/server/scs/ws/WorldService.java
new file mode 100644
index 0000000..b72b825
--- /dev/null
+++ b/server/scs/ws/WorldService.java
@@ -0,0 +1,138 @@
+package psl.chime4.server.scs.ws;
+
+import psl.chime4.server.scs.*;
+import psl.chime4.server.scs.service.*;
+import psl.chime4.server.scs.auth.*;
+import psl.chime4.server.scs.log.*;
+import psl.chime4.server.scs.persist.*;
+import psl.chime4.server.scs.ws.view.*;
+import psl.chime4.server.ces.*;
+
+import java.util.*;
+
+/**
+ * Defines a world that exists on the server.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class WorldService extends AbstractService
+{
+   PersistenceService persistenceService;
+   AuthenticationService authService;
+   EventService eventService;
+   LoggingService loggingService;
+
+   String eventServerHost;
+   int eventServerPort;
+   String uniqueTopic;
+
+   /** keep track of logged in users **/
+   UserInfoService userInfoService;
+
+   /** World being managed by this service **/
+   World world;
+
+   /** event handler for handling events **/
+   EventHandler eventHandler;
+
+   /** default theme that is applied to all first-time users **/
+   Theme defaultTheme = new Theme();
+
+   /**
+    * Initialize the Service. At this point the Service has not started.
+    *
+    * @param params parameters passed from server.xml
+    * @throws ServiceException
+    *        if the service cannot initialize itself
+    */
+   public void initialize(ServiceParamMap params) throws ServiceException
+   {
+      if (params == null)
+      {
+         String msg = "World Service needs parameters!";
+         throw new ServiceException(msg);
+      }
+
+      // get the context
+      ServiceContext context = getServiceContext();
+      if (context == null)
+      {
+         String msg = "no ServiceContext set!";
+         throw new ServiceException(msg);
+      }
+
+      // get the the persistence service
+      persistenceService =
+         (PersistenceService)
+            params.getParam("persistenceService").getValue();
+
+      // get the name of the auth service and set it
+      authService =
+         (AuthenticationService) params.getParam("authService").getValue();
+
+      // get the name of the event service
+      eventService =
+         (EventService) params.getParam("eventService").getValue();
+
+      // get the logging service
+      loggingService =
+         (LoggingService) params.getParam("loggingService").getValue();
+
+      // get the event server host
+      eventServerHost = params.getParam("eventServerHost").getValueAsString();
+
+      // get the event server port
+      eventServerPort = params.getParam("eventServerPort").getValueAsInt();
+
+      // get the unique topic
+      uniqueTopic = params.getParam("uniqueTopic").getValueAsString();
+
+      // create the user info service
+      userInfoService = new UserInfoService();
+      userInfoService.setWorldService(this);
+      userInfoService.setPersistenceService(persistenceService);
+
+      // now register with the event service on our unique topic for our
+      // primary event server
+      eventHandler = new WorldServiceEventHandler(this);
+      try
+      {
+         eventService.openConnection(eventServerHost, eventServerPort);
+         eventService.registerEventHandler(eventServerHost, eventServerPort,
+                                           uniqueTopic, eventHandler);
+      }
+      catch (EventServiceException es)
+      {
+         String msg = "couldn't register with event server!";
+         throw new ServiceException(msg, es);
+      }
+
+      // create the world
+      world = (World) persistenceService.create(World.class);
+      world.setWorldService(this);
+      world.setPersistenceService(persistenceService);
+      world.initialize();
+
+      // create the default theme
+      defaultTheme = new Theme();
+   }
+
+   /**
+    * Start the Service. At this point the service is running.
+    *
+    * @throws ServiceException
+    *        if the service cannot start for some reason
+    */
+   public void start() throws ServiceException
+   {
+   }
+
+   /**
+    * Shut the Service down. The Service has roughly two minutes to shutdown
+    * before it will be forcefully shutdown.
+    */
+   public void stop()
+   {
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/WorldServiceEventHandler.java b/server/scs/ws/WorldServiceEventHandler.java
new file mode 100644
index 0000000..32cf2d8
--- /dev/null
+++ b/server/scs/ws/WorldServiceEventHandler.java
@@ -0,0 +1,248 @@
+package psl.chime4.server.scs.ws;
+
+import psl.chime4.server.ces.*;
+import psl.chime4.server.scs.*;
+import psl.chime4.server.scs.log.*;
+import psl.chime4.server.scs.service.*;
+import psl.chime4.server.scs.ws.*;
+import psl.chime4.server.scs.ws.event.*;
+import psl.chime4.server.scs.ws.data.*;
+import psl.chime4.server.scs.ws.view.*;
+import psl.chime4.server.scs.ws.view.render.*;
+import psl.chime4.server.scs.persist.*;
+import psl.chime4.server.scs.auth.*;
+
+
+/**
+ * Embodies all of the event-handling logic for a given WorldService.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class WorldServiceEventHandler implements EventHandler
+{
+   /** WorldService that created us **/
+   private WorldService wService;
+
+   /**
+    * Create a new event handler to handle events for the given world.
+    *
+    * @param ws WorldService that created us
+    * @throws IllegalArgumentException
+    *         if <code>ws</code> is <code>null</code>
+    **/
+   public WorldServiceEventHandler(WorldService ws)
+   {
+      if (ws == null)
+      {
+         String msg = "world service cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      this.wService = ws;
+   }
+
+   /**
+    * Consume an event. If the event is passed, the handler can be sure that
+    * it recieved it because it met the necessary criteria.
+    *
+    * @param event Event that met the handler's criteria
+    */
+   public void handleEvent(Event event)
+   {
+      wService.loggingService.info("WS", "Got Event: " + event);
+
+      // map the event into a WorldEvent
+      WorldEvent wevent = WorldEventMapper.cesToWorld(event);
+
+      switch (wevent.EventCode)
+      {
+         case EventConstants.WorldLogin:
+            handleEvent((WorldLoginEvent) wevent);
+            break;
+
+         case EventConstants.WorldEntry:
+            handleEvent((WorldEntryEvent) wevent);
+            break;
+
+         default:
+            handleEvent(wevent);
+      }
+   }
+
+   /**
+    * Generic handler event. This means that no specific handler was created.
+    * This method should never be called.
+    *
+    * @param wevent WorldEvent that's unknown
+    **/
+   protected void handleEvent(WorldEvent wevent)
+   {
+      LoggingService lService = wService.loggingService;
+
+      lService.severe("WS", "Unknown Event: " + wevent);
+   }
+
+   /**
+    * Handle the world login event.
+    *
+    * @todo Make sure that two clients will not both log in with the same
+    *       name.
+    *
+    * @param wle World Login Event sent by the client
+    **/
+   protected void handleEvent(WorldLoginEvent wle)
+   {
+      if (wle == null)
+      {
+         String msg = "wle cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      // get the user's name, ticket and topic
+      String username = wle.Username;
+      byte[] ticket = wle.Ticket;
+      String topic = wle.UniqueTopic;
+
+      // get the name of the world and event server stuff
+      String worldName = wService.getServiceName();
+      String eServerHost = wService.eventServerHost;
+      int eServerPort = wService.eventServerPort;
+
+      // get the services needed to handle this event
+      AuthenticationService aService = wService.authService;
+      Theme defaultTheme = wService.defaultTheme;
+      EventService eService = wService.eventService;
+      LoggingService lService = wService.loggingService;
+
+      // try to authenticate the user
+      String authResult = "bad login";
+      try
+      {
+         authResult = aService.authenticate(username, ticket);
+      }
+      catch (ServiceException se)
+      {
+         // authentication service has failed take appropriate action
+      }
+
+      WorldEvent reply;
+
+      if (authResult == null)
+      {
+         // authentication was successful, send back a login success
+         reply = new WorldLoginSuccessEvent(worldName);
+
+         // create a user info object for the user and initialize it
+         UserInfo user = wService.userInfoService.newUser(username, topic);
+         user.setAuthenticated(true);
+         user.setCurrentTheme(defaultTheme);
+         user.setEventBridge(new EventBridge(eServerHost,
+                                             eServerPort, eService)
+                            );
+
+         lService.info("WS", "User Logged In: " + user);
+      } else
+      {
+         // authentication failed
+         reply = new WorldLoginFailureEvent(worldName, authResult);
+
+         lService.info("WS", "User Failed to Log In: " + username);
+      }
+
+      // try to send the reply
+      try
+      {
+         Event event = eService.createEmptyEvent();
+         event = reply.toCesEvent(event);
+         eService.publish(eServerHost, eServerPort, topic, event);
+      }
+      catch (EventServiceException ese)
+      {
+         // event service has failed, take appropriate action
+      }
+   }
+
+   /**
+    * Handle the World Entry event when the client attempts to enter the
+    * world for the first time.
+    *
+    * @param wee event representing the request
+    * @throws IllegalArgumentException
+    *         if <code>event</code> is <code>null</code>
+    **/
+   protected void handleEvent(WorldEntryEvent wee)
+   {
+      if (wee == null)
+      {
+         String msg = "wee cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      UserInfoService uiService = wService.userInfoService;
+      EventService eService = wService.eventService;
+      PersistenceService pService = wService.persistenceService;
+      World world = wService.World;
+      Theme theme = wService.defaultTheme;
+
+      String worldName = wService.getServiceName();
+      int lobbyRoomID = wService.world.getLobbyRoom().getInstanceID();
+      int worldDoorID = wService.world.getLobbyEntrance().getInstanceID();
+
+      // get the user who sent this event
+      UserInfo user = (UserInfo) uiService.getUser(wee.Username);
+
+      // if the user has never logged in or is not authenticated, ignore
+      // the event
+      if ((user == null) || !(user.isAuthenticated()))
+      {
+         return;
+      }
+
+      // return a world entry success by default, in the future security
+      // would be implemented. this world entry tells the client to enter the
+      // lobby through the special world door
+      WorldEvent reply = new WorldEntrySuccessEvent(
+         worldName, lobbyRoomID, worldDoorID);
+
+      // construct a new HumanAvatar to represent this user in the world
+      try
+      {
+         UserAvatar avatar = (UserAvatar) pService.create(UserAvatar.class);
+         avatar.setUserInfo(user);
+
+
+         // make it look like a red cube
+         LocatedView view = (LocatedView) pService.create(LocatedView.class);
+         CubeGeometry cubeGeom =
+            (CubeGeometry) pService.create(CubeGeometry.class);
+         view.setGeometry(cubeGeom);
+
+         RenderGeometryInstruction ri =
+            (RenderGeometryInstruction)
+               pService.create(RenderGeometryInstruction.class);
+
+         view.setRenderInstruction(ri);
+
+         // put it into the theme
+      }
+      catch (ServiceException se)
+      {
+         // the persistence service failed so take appropriate action
+      }
+
+
+      // now send the event to the user
+      try
+      {
+         Event event = eService.createEmptyEvent();
+         event = reply.toCesEvent(event);
+         user.sendEvent(event);
+      }
+      catch (EventServiceException ese)
+      {
+         // event service has failed, take appropriate action
+      }
+   }
+}
+
\ No newline at end of file
diff --git a/server/scs/ws/XmlSerializable.java b/server/scs/ws/XmlSerializable.java
new file mode 100644
index 0000000..cfefdab
--- /dev/null
+++ b/server/scs/ws/XmlSerializable.java
@@ -0,0 +1,30 @@
+package psl.chime4.server.scs.ws;
+
+import org.jdom.*;
+
+/**
+ * A class who implements this interface indicates that it can write out its
+ * total state to XML.
+ *
+ * Currently XML serialization happens using JDOM. This is very slow and ugly
+ * and it leads to the creation and destruction of hundreds of unnecessary
+ * object. In the future a mechanism will be created for creating XML in a
+ * SAX-like manner like the XmlWriter class in .NET.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public interface XmlSerializable
+{
+   /**
+    * Write out the current state of the object to XML. The serilizable
+    * instance is passed a node to which it should construct a new node and
+    * add to it. The serilizable instance may not alter the passed node in
+    * any other manner.
+    *
+    * @param node node to add a child to representing the state
+    * @throws IllegalArgumentException
+    *         if <code>node</code> is <code>null</code>
+    **/
+   public void writeObject(Element node);
+}
\ No newline at end of file
diff --git a/server/scs/ws/data/Avatar.java b/server/scs/ws/data/Avatar.java
new file mode 100644
index 0000000..b90309c
--- /dev/null
+++ b/server/scs/ws/data/Avatar.java
@@ -0,0 +1,35 @@
+package psl.chime4.server.scs.ws.data;
+
+/**
+ * Represents an 'active' object in the world that can move around and
+ * intiate actions.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class Avatar extends LocatedWorldObject
+{
+   /** current location of the avatar **/
+   private Room currentLoc;
+
+   /**
+    * Get the current location of the avatar.
+    *
+    * @return current location of the avatar
+    **/
+   public Room getCurrentLocation()
+   {
+      return currentLoc;
+   }
+
+   /**
+    * Set the current location of the avatar.
+    *
+    * @param loc new current location for the avatar
+    **/
+   public void setCurrentLocation(Room loc)
+   {
+      this.currentLoc = loc;
+   }
+}
+
diff --git a/server/scs/ws/data/Door.java b/server/scs/ws/data/Door.java
new file mode 100644
index 0000000..ace1a3c
--- /dev/null
+++ b/server/scs/ws/data/Door.java
@@ -0,0 +1,57 @@
+package psl.chime4.server.scs.ws.data;
+
+/**
+ * Represents a connection from one room to another.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class Door extends LocatedWorldObject
+{
+   /** room this door is leading from **/
+   private Room source;
+
+   /** room this door is goes to **/
+   private Room destination;
+
+   /**
+    * Get the room that this door is leading from.
+    *
+    * @return room this door leads from
+    **/
+   public Room getSource()
+   {
+      return source;
+   }
+
+   /**
+    * Set the room that this door leads from.
+    *
+    * @param source door this from
+    **/
+   public void setSource(Room source)
+   {
+      this.source = source;
+   }
+
+   /**
+    * Get the room that this door leads to.
+    *
+    * @return room this door goes to
+    **/
+   public Room getDestination()
+   {
+      return destination;
+   }
+
+   /**
+    * Set the destination that this door leads to.
+    *
+    * @param dest room this room leads to
+    **/
+   public void setDestination(Room dest)
+   {
+      this.destination = dest;
+   }
+}
+
\ No newline at end of file
diff --git a/server/scs/ws/data/LocatedWorldObject.java b/server/scs/ws/data/LocatedWorldObject.java
new file mode 100644
index 0000000..f94b6e4
--- /dev/null
+++ b/server/scs/ws/data/LocatedWorldObject.java
@@ -0,0 +1,34 @@
+package psl.chime4.server.scs.ws.data;
+
+/**
+ * Represents a WorldObject that has a current location; that is it exists
+ * inside a Room.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class LocatedWorldObject extends WorldObject
+{
+   /** current location of the object **/
+   private Room currentLoc;
+
+   /**
+    * Get the current location of this world object.
+    *
+    * @return current location of this world object
+    **/
+   public Room getCurrentLocation()
+   {
+      return currentLoc;
+   }
+
+   /**
+    * Set the current location of this world object.
+    *
+    * @param loc current location of this world object
+    **/
+   public void setCurrentLocation(Room loc)
+   {
+      this.currentLoc = loc;
+   }
+}
diff --git a/server/scs/ws/data/MetadataWorldObject.java b/server/scs/ws/data/MetadataWorldObject.java
new file mode 100644
index 0000000..6d121ea
--- /dev/null
+++ b/server/scs/ws/data/MetadataWorldObject.java
@@ -0,0 +1,34 @@
+package psl.chime4.server.scs.ws.data;
+
+import psl.chime4.server.scs.metadata.*;
+
+/**
+ * Represents a piece of metadata in the world.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class MetadataWorldObject extends WorldObject
+{
+   private Metadata mData;
+
+   /**
+    * Get the piece of Metadata represented by this room.
+    *
+    * @return metadata this object represents
+    **/
+   public Metadata getMetadata()
+   {
+      return mData;
+   }
+
+   /**
+    * Set the piece of Metadata represented by this room.
+    *
+    * @param mdata the metadata this object represents
+    **/
+   public void setMetadata(Metadata mData)
+   {
+      this.mData = mData;
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/data/RemoteRoom.java b/server/scs/ws/data/RemoteRoom.java
new file mode 100644
index 0000000..785cd0a
--- /dev/null
+++ b/server/scs/ws/data/RemoteRoom.java
@@ -0,0 +1,79 @@
+package psl.chime4.server.scs.ws.data;
+
+/**
+ * Represents a room on a remote server.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class RemoteRoom extends Room
+{
+   /** host of the remote server **/
+   private String host;
+
+   /** port of the remote server process **/
+   private int port;
+
+   /** unique topic for the remote server **/
+   private String topic;
+
+   /**
+    * Get the host of the remote server.
+    *
+    * @return host of the remote server
+    **/
+   public String getRemoteHost()
+   {
+      return host;
+   }
+
+   /**
+    * Set the host of the remote server.
+    *
+    * @param host host of the remote server
+    **/
+   public void setRemoteHost(String host)
+   {
+      this.host = host;
+   }
+
+   /**
+    * Get the port of the remote server.
+    *
+    * @return port of the remote server
+    **/
+   public int getRemotePort()
+   {
+      return port;
+   }
+
+   /**
+    * Set the port of the remote server.
+    *
+    * @param port port of the remote server
+    **/
+   public void setRemotePort(int port)
+   {
+      this.port = port;
+   }
+
+   /**
+    * Get the unique topic for the remote server.
+    *
+    * @return topic for the remote server
+    **/
+   public String getRemoteTopic()
+   {
+      return topic;
+   }
+
+   /**
+    * Set the unique topic for the remote server.
+    *
+    * @param topic topic for the remote server
+    **/
+   public void setRemoteTopic(String topic)
+   {
+      this.topic = topic;
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/data/Room.java b/server/scs/ws/data/Room.java
new file mode 100644
index 0000000..b8a3a5f
--- /dev/null
+++ b/server/scs/ws/data/Room.java
@@ -0,0 +1,151 @@
+package psl.chime4.server.scs.ws.data;
+
+import java.util.*;
+
+/**
+ * Represents a Room in the world.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class Room extends MetadataWorldObject
+{
+   private Set doors = new HashSet();
+   private Set contents = new HashSet();
+
+   /** the last time the room's structure changed **/
+   private long structureTime = System.currentTimeMillis();
+
+   /**
+    * Add a piece of content to the room.
+    *
+    * @param wobj World object to add to the room
+    * @throws IllegalArgumentException
+    *         if <code>wobj</code> is <code>null</code>
+    **/
+   public void addContent(LocatedWorldObject wobj)
+   {
+      if (wobj == null)
+      {
+         String msg = "wobj cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      synchronized(contents)
+      {
+         contents.add(wobj);
+      }
+
+      // update the world object's current location
+      wobj.setCurrentLocation(this);
+   }
+
+   /**
+    * Remove a piece of content from the room.
+    *
+    * @param wobj World object to remove from this room
+    **/
+   public void removeContent(LocatedWorldObject wobj)
+   {
+      if ((wobj != null) && (contents != null))
+      {
+         synchronized(contents)
+         {
+            if (contents.remove(wobj))
+            {
+               wobj.setCurrentLocation(null);
+            }
+         }
+      }
+   }
+
+   /**
+    * Return an iterator over all the contents in the room.
+    *
+    * @return iterator over the contents in the room
+    **/
+   public Iterator contents()
+   {
+      if (contents == null)
+      {
+         return Collections.EMPTY_SET.iterator();
+      } else
+      {
+         return contents.iterator();
+      }
+   }
+
+   /**
+    * Add a door to the room.
+    *
+    * @param door door to add to the room
+    * @throws IllegalArgumentException
+    *         if <code>door</code> is <code>null</code>
+    **/
+   public void addDoor(Door door)
+   {
+      if (door == null)
+      {
+         String msg = "door cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      // make sure the door leads from us
+      door.setSource(this);
+
+      synchronized(doors)
+      {
+         doors.add(door);
+      }
+
+      // timestamp this change in the room's structure
+      structureChanged();
+   }
+
+   /**
+    * Remove a door from the room.
+    *
+    * @param door door to the remove from the room
+    **/
+   public void removeDoor(Door door)
+   {
+      if ((door != null) && (doors != null))
+      {
+         synchronized(doors)
+         {
+            if (doors.remove(door))
+            {
+               door.setSource(null);
+               structureChanged();
+            }
+         }
+      }
+   }
+
+   /**
+    * Return an iterator over all the doors in the room.
+    *
+    * @return iterator over all the doors in the room
+    **/
+   public Iterator doors()
+   {
+      if (doors == null)
+      {
+         return Collections.EMPTY_SET.iterator();
+      } else
+      {
+         return doors.iterator();
+      }
+   }
+
+   /**
+    * Called when the room's structure has changed. Updates the time changed.
+    **/
+   protected void structureChanged()
+   {
+      structureTime = System.currentTimeMillis();
+   }
+}
+
+
+
diff --git a/server/scs/ws/data/UserAvatar.java b/server/scs/ws/data/UserAvatar.java
new file mode 100644
index 0000000..28f07b1
--- /dev/null
+++ b/server/scs/ws/data/UserAvatar.java
@@ -0,0 +1,37 @@
+package psl.chime4.server.scs.ws.data;
+
+import psl.chime4.server.scs.ws.UserInfo;
+
+/**
+ * Represents a human/user avatar in the world.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class UserAvatar extends Avatar
+{
+   /** user info obj for this avatar **/
+   private UserInfo user;
+
+   /**
+    * Get info about the user for this avatar.
+    *
+    * @return info about the user for this avatar
+    **/
+   public UserInfo getUserInfo()
+   {
+      return user;
+   }
+
+   /**
+    * Set info about the user for this avatar.
+    *
+    * @param user info about the user for this avatar
+    **/
+   public void setUserInfo(UserInfo user)
+   {
+      this.user = user;
+   }
+}
+
+
\ No newline at end of file
diff --git a/server/scs/ws/data/WorldObject.java b/server/scs/ws/data/WorldObject.java
new file mode 100644
index 0000000..61a24dd
--- /dev/null
+++ b/server/scs/ws/data/WorldObject.java
@@ -0,0 +1,24 @@
+package psl.chime4.server.scs.ws.data;
+
+import psl.chime4.server.scs.persist.*;
+
+/**
+ * Represents an object in the world.
+ *
+ * @todo Override hashCode() and equals() in this class.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public abstract class WorldObject extends PersistentObject
+{
+   /**
+    * Get the instance id for this world object.
+    *
+    * @return instance id for this world object
+    **/
+   public int getInstanceID()
+   {
+      return super.getPersistenceID();
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/view/LocatedView.java b/server/scs/ws/view/LocatedView.java
new file mode 100644
index 0000000..f21ce65
--- /dev/null
+++ b/server/scs/ws/view/LocatedView.java
@@ -0,0 +1,77 @@
+package psl.chime4.server.scs.ws.view;
+
+/**
+ * Represents the View of an object that has a location in the world. This
+ * is essentially every object except for Rooms (which are described by
+ * views).
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class LocatedView extends View
+{
+   /** coordinates in the world **/
+   private int xCoord;
+   private int yCoord;
+   private int zCoord;
+
+   /**
+    * Get the x-coordinate of the object.
+    *
+    * @return xCoord of the object
+    **/
+   public int getX()
+   {
+      return xCoord;
+   }
+
+   /**
+    * Set the x-coordinate of the object.
+    *
+    * @param x x-coordinate of the object
+    **/
+   public void setX(int x)
+   {
+      this.xCoord = x;
+   }
+
+   /**
+    * Get the y-coordinate of the object.
+    *
+    * @return y coord of the object
+    **/
+   public int getY()
+   {
+      return yCoord;
+   }
+
+   /**
+    * Set the y coord of the object.
+    *
+    * @param y y-coordinate of the object
+    **/
+   public void setY(int y)
+   {
+      this.yCoord = y;
+   }
+
+   /**
+    * Get the z coord of the object.
+    *
+    * @return z coord of the object
+    **/
+   public int getZ()
+   {
+      return zCoord;
+   }
+
+   /**
+    * Set the z-coordinate of the object
+    *
+    * @param z z-coordinate of the object
+    **/
+   public void setZ(int z)
+   {
+      this.zCoord = z;
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/view/Theme.java b/server/scs/ws/view/Theme.java
new file mode 100644
index 0000000..968dbaa
--- /dev/null
+++ b/server/scs/ws/view/Theme.java
@@ -0,0 +1,85 @@
+package psl.chime4.server.scs.ws.view;
+
+import psl.chime4.server.scs.ws.data.*;
+
+import java.util.*;
+
+/**
+ * A Theme represents a mapping between views of objects and the objects
+ * themselves. The Theme is also responsible for mapping object meta-types
+ * to views.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class Theme
+{
+   /** map of all world object to their current views **/
+   private IdentityHashMap viewMap = new IdentityHashMap();
+
+   /**
+    * Place an object with its matching view in the theme.
+    *
+    * @param wobj World Object to put into the theme
+    * @param view View describing what the world object looks like
+    * @throws IllegalArgumentException
+    *         if any parameter is <code>null</code>
+    **/
+   public void putViewMapping(WorldObject wobj, View view)
+   {
+      if ((wobj == null) || (view == null))
+      {
+         String msg = "no parameter can be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      synchronized(viewMap)
+      {
+         viewMap.put(wobj, view);
+      }
+   }
+
+   /**
+    * Remove a view mapping for a specific object from the map.
+    *
+    * @param wobj WorldObject to remove the view for
+    * @return View that was mapped to <code>wobj</code> or <code>null</code>
+    * @throws IllegalArgumentException
+    *         if <code>wobj</code> is <code>null</code>
+    **/
+   public View removeViewMapping(WorldObject wobj)
+   {
+      if (wobj == null)
+      {
+         String msg = "no parameter can be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      synchronized(viewMap)
+      {
+         return (View) viewMap.remove(wobj);
+      }
+   }
+
+   /**
+    * Retreive the View for a given World Object.
+    *
+    * @param wobj WorldObject to retrieve the view for
+    * @return View for <code>wobj</code> or <code>null</code>
+    * @throws IllegalArgumentException
+    *         if <code>wobj</code> is <code>null</code>
+    **/
+   public View getViewMapping(WorldObject wobj)
+   {
+      if (wobj == null)
+      {
+         String msg = "view cannot be null";
+         throw new IllegalArgumentException(msg);
+      }
+
+      synchronized(viewMap)
+      {
+         return (View) viewMap.get(wobj);
+      }
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/view/View.java b/server/scs/ws/view/View.java
new file mode 100644
index 0000000..c96b654
--- /dev/null
+++ b/server/scs/ws/view/View.java
@@ -0,0 +1,84 @@
+package psl.chime4.server.scs.ws.view;
+
+import psl.chime4.server.scs.persist.*;
+import psl.chime4.server.scs.ws.data.*;
+import psl.chime4.server.scs.ws.view.render.*;
+
+/**
+ * Represents what an object looks like in the world. This class can also
+ * be used to describe what rooms in the world look like.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class View extends PersistentObject
+{
+   /** instruction to the 3D engine how to draw this view **/
+   private RenderInstruction renderInstruction;
+
+   /** world object that is being drawn **/
+   private WorldObject wobj;
+
+   /** geometry that defines the shape of this view **/
+   private Geometry geometry;
+
+   /**
+    * Get the render instructions for how to draw this object.
+    *
+    * @return render instruction for how to draw this object
+    **/
+   public RenderInstruction getRenderInstruction()
+   {
+      return renderInstruction;
+   }
+
+   /**
+    * Set the render instruction for how to draw this object.
+    *
+    * @param instr instructions how to draw this object
+    **/
+   public void setRenderInstruction(RenderInstruction instr)
+   {
+      this.renderInstruction = instr;
+   }
+
+   /**
+    * Get the world object being drawn.
+    *
+    * @return world object being drawn
+    **/
+   public WorldObject getWorldObject()
+   {
+      return wobj;
+   }
+
+   /**
+    * Set the world object this room is drawing.
+    *
+    * @param wobj world object that this room is being drawn
+    **/
+   public void setWorldObject(WorldObject wobj)
+   {
+      this.wobj = wobj;
+   }
+
+   /**
+    * Get the geometry defining the general shape of this view.
+    *
+    * @return gemoetry defining the shape of this view
+    **/
+   public Geometry getGeometry()
+   {
+      return geometry;
+   }
+
+   /**
+    * Set the geometry that defines the general shape of this view.
+    *
+    * @param geom geometry defining the shape of the view
+    **/
+   public void setGeometry(Geometry geom)
+   {
+      this.geometry = geom;
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/view/render/ConeGeometry.java b/server/scs/ws/view/render/ConeGeometry.java
new file mode 100644
index 0000000..4114c48
--- /dev/null
+++ b/server/scs/ws/view/render/ConeGeometry.java
@@ -0,0 +1,59 @@
+package psl.chime4.server.scs.ws.view.render;
+
+/**
+ * Represents a cone in space.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class ConeGeometry extends Geometry
+{
+   private float height;
+   private float radius;
+
+   public ConeGeometry()
+   {
+      super.geomCode = RenderConstants.CONE_GEOMETRY;
+      super.geomURI = RenderConstants.CONE_GEOMETRY_URI;
+   }
+
+   /**
+    * Get the height of the cone.
+    *
+    * @return height of the cone
+    **/
+   public float getHeight()
+   {
+      return height;
+   }
+
+   /**
+    * Set the height of the cone.
+    *
+    * @param height height of the cone
+    **/
+   public void setHeight(float height)
+   {
+      this.height = height;
+   }
+
+   /**
+    * Get the radius of the cone.
+    *
+    * @return radius of the cone
+    **/
+   public float getRadius()
+   {
+      return radius;
+   }
+
+   /**
+    * Set the radius of the cone.
+    *
+    * @param radius of the cone
+    **/
+   public void setRadius(float radius)
+   {
+      this.radius = radius;
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/view/render/CubeGeometry.java b/server/scs/ws/view/render/CubeGeometry.java
new file mode 100644
index 0000000..d16ae4b
--- /dev/null
+++ b/server/scs/ws/view/render/CubeGeometry.java
@@ -0,0 +1,80 @@
+package psl.chime4.server.scs.ws.view.render;
+
+/**
+ * This defines a simple geometry for a cube in space.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class CubeGeometry extends Geometry
+{
+   private float width;
+   private float height;
+   private float length;
+
+   public CubeGeometry()
+   {
+      super.geomCode = RenderConstants.CUBE_GEOMETRY;
+      super.geomURI = RenderConstants.CUBE_GEOMETRY_URI;
+   }
+
+   /**
+    * Get the width of the cube.
+    *
+    * @return width of the cube
+    **/
+   public float getWidth()
+   {
+      return width;
+   }
+
+   /**
+    * Set the width of the cube.
+    *
+    * @param width width of the cube
+    **/
+   public void setWidth(float width)
+   {
+      this.width = width;
+   }
+
+   /**
+    * Get the height of the cube.
+    *
+    * @return height of the cube
+    **/
+   public float getHeight()
+   {
+      return height;
+   }
+
+   /**
+    * Set the height of the cube.
+    *
+    * @param height height of the cube
+    **/
+   public void setHeight(float height)
+   {
+      this.height = height;
+   }
+
+   /**
+    * Get the length of the cube.
+    *
+    * @return length of the cube
+    **/
+   public float getLength()
+   {
+      return length;
+   }
+
+   /**
+    * Set the length of the cube.
+    *
+    * @param length length of the cube
+    **/
+   public void setLength(float length)
+   {
+      this.length = length;
+   }
+}
diff --git a/server/scs/ws/view/render/CylinderGeometry.java b/server/scs/ws/view/render/CylinderGeometry.java
new file mode 100644
index 0000000..1dd9233
--- /dev/null
+++ b/server/scs/ws/view/render/CylinderGeometry.java
@@ -0,0 +1,61 @@
+package psl.chime4.server.scs.ws.view.render;
+
+/**
+ * Represents the geometry of a cylinder.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class CylinderGeometry extends Geometry
+{
+   private float radius;
+   private float height;
+
+   public CylinderGeometry()
+   {
+      super.geomCode = RenderConstants.CYLINDER_GEOMETRY;
+      super.geomURI = RenderConstants.CYLINDER_GEOMETRY_URI;
+   }
+
+   /**
+    * Get the radius of the cylinder.
+    *
+    * @return radius of the cylinder
+    **/
+   public float getRadius()
+   {
+      return radius;
+   }
+
+   /**
+    * Set the radius of the cylinder.
+    *
+    * @param radius radius of the cylinder
+    **/
+   public void setRadius(float radius)
+   {
+      this.radius = radius;
+   }
+
+   /**
+    * Get the height of the cylinder.
+    *
+    * @return height of the cylinder
+    **/
+   public float getHeight()
+   {
+      return height;
+   }
+
+   /**
+    * Set the height of the cylinder.
+    *
+    * @param height height of the cylinder
+    **/
+   public void setHeight(float height)
+   {
+      this.height = height;
+   }
+}
+
+
diff --git a/server/scs/ws/view/render/Geometry.java b/server/scs/ws/view/render/Geometry.java
new file mode 100644
index 0000000..50f8935
--- /dev/null
+++ b/server/scs/ws/view/render/Geometry.java
@@ -0,0 +1,52 @@
+package psl.chime4.server.scs.ws.view.render;
+
+import psl.chime4.server.scs.persist.*;
+
+/**
+ * Defines a geometry; that is a shape that exists in space independent of
+ * location.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public abstract class Geometry extends PersistentObject
+{
+   /** code defining this geometry **/
+   protected int geomCode;
+
+   /** uri defining this geometry **/
+   protected String geomURI;
+
+   /**
+    * Get the numeric code for this geometry.
+    *
+    * @return code for this geometry
+    **/
+   public int getGemetryCode()
+   {
+      return geomCode;
+   }
+
+   /**
+    * Get the uri for this geometry.
+    *
+    * @return uri for this geometry
+    **/
+   public String getGeometryURI()
+   {
+      return geomURI;
+   }
+
+   /**
+    * Calculate the bounding box for this geometry and stores it in the
+    * passed CubeGeomtetry.
+    *
+    * @param cubeGeometry geometry to store the bounding box info
+    * @throws IllegalArgumentException
+    *         if <code>cubeGeometry</code> is <code>null</code>
+    **/
+   public void calculateBoundingBox(CubeGeometry cubeGeometry)
+   {
+      // @todo implement this method
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/view/render/PolygonGeometry.java b/server/scs/ws/view/render/PolygonGeometry.java
new file mode 100644
index 0000000..a59794a
--- /dev/null
+++ b/server/scs/ws/view/render/PolygonGeometry.java
@@ -0,0 +1,99 @@
+package psl.chime4.server.scs.ws.view.render;
+
+/**
+ * Defines a set of vertices that can define any random shape that has been
+ * normalized.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class PolygonGeometry extends Geometry
+{
+   /** number of vertices in the geometry **/
+   private int numVertices;
+
+   /** array of x-verts **/
+   protected float[] xCoords;
+
+   /** array of y-verts **/
+   protected float[] yCoords;
+
+   /** array of z-verts **/
+   protected float[] zCoords;
+
+   public PolygonGeometry()
+   {
+      super.geomCode = RenderConstants.POLYGON_GEOMETRY;
+      super.geomURI = RenderConstants.POLYGON_GEOMETRY_URI;
+   }
+
+   /**
+    * Get the number of vertices in the geometry.
+    *
+    * @return number of vertices in the geometry
+    **/
+   public int getNumVertices()
+   {
+      return numVertices;
+   }
+
+   /**
+    * Set the number of vertices in the geometry.
+    *
+    * @param numVertices number of vertices in the geometry
+    **/
+   public void setNumVertices(int numVertices)
+   {
+      this.numVertices = numVertices;
+   }
+
+   /**
+    * Set the n-th vertex of the geometry.
+    *
+    * @param n nth vertex of the geometry
+    * @param x x-coord of the vertex
+    * @param y y-coord of the vertex
+    * @param z z-coord of the vertex
+    **/
+   public void setNthVertex(int n, float x, float y, float z)
+   {
+      xCoords[n] = x;
+      yCoords[n] = y;
+      zCoords[n] = z;
+   }
+
+   /**
+    * Get the x coordinate of the n-th of the geometry.
+    *
+    * @param n number of the vertex to retrieve
+    * @return x coordinate of the nth vertex
+    **/
+   public float getNthX(int n)
+   {
+      return xCoords[n];
+   }
+
+   /**
+    * Get the y coordinate of the n-th vertex of the geometry.
+    *
+    * @param n number of the vertex to retrieve
+    * @return y coordinate of the nth vertex
+    **/
+   public float getNthY(int n)
+   {
+      return yCoords[n];
+   }
+
+   /**
+    * Get the z coordinate of the n-th vertex of the geometry.
+    *
+    * @param n number of the vertex to retrieve
+    * @return z coordinate of the nth vertex
+    **/
+   public float getNthZ(int n)
+   {
+      return zCoords[n];
+   }
+}
+
+
diff --git a/server/scs/ws/view/render/Render3DTextInstruction.java b/server/scs/ws/view/render/Render3DTextInstruction.java
new file mode 100644
index 0000000..ee99e54
--- /dev/null
+++ b/server/scs/ws/view/render/Render3DTextInstruction.java
@@ -0,0 +1,88 @@
+package psl.chime4.server.scs.ws.view.render;
+
+/**
+ * Tells the renderer to draw 3D text at the current context.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class Render3DTextInstruction extends RenderInstruction
+{
+   /** string to render **/
+   private String text;
+
+   /** vector to draw the text in **/
+   private float xOri;
+   private float yOri;
+   private float zOri;
+
+   public Render3DTextInstruction()
+   {
+      super.instructionCode = RenderConstants.RENDER_3D_TEXT;
+      super.instructionURI = RenderConstants.RENDER_3D_TEXT_URI;
+   }
+
+   /**
+    * Get the text to render.
+    *
+    * @return text to render
+    **/
+   public String getText()
+   {
+      return text;
+   }
+
+   /**
+    * Set the text of the render.
+    *
+    * @param text the text to render
+    **/
+   public void setText(String text)
+   {
+      this.text = text;
+   }
+
+   /**
+    * Get the x-orientation to render the text in.
+    *
+    * @return x-orientation to render the text in
+    **/
+   public float getXOrientation()
+   {
+      return xOri;
+   }
+
+   /**
+    * Get the y-orientation to render the text in.
+    *
+    * @return y-orientation to render the text in
+    **/
+   public float getYOrientation()
+   {
+      return yOri;
+   }
+
+   /**
+    * Get the z-orientation to render the text in.
+    *
+    * @return z-orientation to render the text in
+    **/
+   public float getZOrientation()
+   {
+      return zOri;
+   }
+
+   /**
+    * Set the orientation to render the text in.
+    *
+    * @param xOri orientation on the x-axis
+    * @param yOri orientation on the y-axis
+    * @param zOri orientation on the z-axis
+    **/
+   public void setOrientation(float xOri, float yOri, float zOri)
+   {
+      this.xOri = xOri;
+      this.yOri = yOri;
+      this.zOri = zOri;
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/view/render/RenderBillboardInstruction.java b/server/scs/ws/view/render/RenderBillboardInstruction.java
new file mode 100644
index 0000000..848f678
--- /dev/null
+++ b/server/scs/ws/view/render/RenderBillboardInstruction.java
@@ -0,0 +1,34 @@
+package psl.chime4.server.scs.ws.view.render;
+
+import psl.chime4.server.scs.ws.view.image.*;
+
+/**
+ * Tells the 3D Renderer to draw a 2D billboard image that is always facing
+ * the camera straight on.
+ *
+ * @author Azubuko Obele
+ **/
+public class RenderBillboardInstruction extends RenderInstruction
+{
+   private ImageInfo image;
+
+   /**
+    * Get the image for the billboard to render.
+    *
+    * @return info about the image to render
+    **/
+   public ImageInfo getImage()
+   {
+      return image;
+   }
+
+   /**
+    * Set the information about the image to render as a billboard.
+    *
+    * @param info image info about the render
+    **/
+   public void setImage(ImageInfo image)
+   {
+      this.image = image;
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/view/render/RenderConstants.java b/server/scs/ws/view/render/RenderConstants.java
new file mode 100644
index 0000000..1dc47e1
--- /dev/null
+++ b/server/scs/ws/view/render/RenderConstants.java
@@ -0,0 +1,79 @@
+package psl.chime4.server.scs.ws.view.render;
+
+/**
+ * Constants that have to deal with the distrubted 3D engine.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public interface RenderConstants
+{
+   /** colors defining the different constants **/
+   public static final int COLOR_WHITE = 0;
+   public static final int COLOR_BLACK = 10;
+   public static final int COLOR_BLUE = 20;
+   public static final int COLOR_RED = 30;
+   public static final int COLOR_GREEN = 40;
+   public static final int COLOR_YELLOW = 50;
+   public static final int COLOR_MAGENTA = 60;
+   public static final int COLOR_CYAN = 70;
+   public static final int COLOR_TRANSPARENT = 80;
+
+   /** constants and uris defining the different instructions **/
+   public static final int RENDER_3D_TEXT = 10;
+   public static final String RENDER_3D_TEXT_URI = "ri:render_3d_text";
+
+   public static final int RENDER_BILLBOARD = 20;
+   public static final String RENDER_BILLBOARD_URI = "ri:render_billboard";
+
+   public static final int RENDER_FOG_EFFECT = 30;
+   public static final String RENDER_FOG_EFFECT_URI = "ri:render_fog_effect";
+
+   public static final int RENDER_GEOMETRY = 40;
+   public static final String RENDER_GEOMETRY_URI = "ri:render_geometry";
+
+   public static final int RENDER_INSTRUCTION_CHAIN = 50;
+   public static final String RENDER_INSTRUCTION_CHAIN_URI =
+      "ri:render_instruction_chain";
+
+   public static final int RENDER_LIGHT = 60;
+   public static final String RENDER_LIGHT_URI = "ri:render_light";
+
+   public static final int RENDER_MODEL = 70;
+   public static final String RENDER_MODEL_URI = "ri:render_model";
+
+   public static final int RENDER_ROTATION = 80;
+   public static final String RENDER_ROTATION_URI = "ri:render_rotation";
+
+   public static final int RENDER_SCALING = 90;
+   public static final String RENDER_SCALING_URI = "ri:render_scaling";
+
+   public static final int RENDER_SOUND = 100;
+   public static final String RENDER_SOUND_URI = "ri:render_sound";
+
+   public static final int RENDER_SPEECH = 110;
+   public static final String RENDER_SPEECH_URI = "ri:render_speech";
+
+   public static final int RENDER_TEXTURE = 120;
+   public static final String RENDER_TEXTURE_URI = "ri:render_texture";
+
+   public static final int RENDER_TRANSLATION = 130;
+   public static final String RENDER_TRANSLATION_URI =
+      "ri:render_translation";
+
+   /** constants defining the different geometries **/
+   public static final int CONE_GEOMETRY = 0;
+   public static final String CONE_GEOMETRY_URI = "geom:cone";
+
+   public static final int CUBE_GEOMETRY = 10;
+   public static final String CUBE_GEOMETRY_URI = "geom:cube";
+
+   public static final int CYLINDER_GEOMETRY = 20;
+   public static final String CYLINDER_GEOMETRY_URI = "geom:cylinder";
+
+   public static final int SPHERE_GEOMETRY = 30;
+   public static final String SPHERE_GEOMETRY_URI = "geom:sphere";
+
+   public static final int POLYGON_GEOMETRY = 40;
+   public static final String POLYGON_GEOMETRY_URI = "geom:polygon";
+}
diff --git a/server/scs/ws/view/render/RenderFogEffectInstruction.java b/server/scs/ws/view/render/RenderFogEffectInstruction.java
new file mode 100644
index 0000000..c09830b
--- /dev/null
+++ b/server/scs/ws/view/render/RenderFogEffectInstruction.java
@@ -0,0 +1,85 @@
+package psl.chime4.server.scs.ws.view.render;
+
+/**
+ * Tells the 3D Renderer to draw fog within a sphere.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class RenderFogEffectInstruction extends RenderInstruction
+{
+   /** the density of the fog to render **/
+   private float density;
+
+   /** sphere of radius to render the fog in **/
+   private int radius;
+
+   /** color of the fog **/
+   private int color;
+
+   public RenderFogEffectInstruction()
+   {
+      super.instructionCode = RenderConstants.RENDER_FOG_EFFECT;
+      super.instructionURI = RenderConstants.RENDER_FOG_EFFECT_URI;
+   }
+
+   /**
+    * Get the density of the fog to render.
+    *
+    * @return density of the fog to render
+    **/
+   public float getDensity()
+   {
+      return density;
+   }
+
+   /**
+    * Set the density of the fog to render.
+    *
+    * @param density density of the fog to render
+    **/
+   public void setDensity(float density)
+   {
+      this.density = density;
+   }
+
+   /**
+    * Get the radius of the field to render the fog in.
+    *
+    * @return radius of the fog to render the fog in
+    **/
+   public int getRadius()
+   {
+      return radius;
+   }
+
+   /**
+    * Set the radius of the field to render the fog in.
+    *
+    * @param radius radius of the field to render the fog in
+    **/
+   public void setRadius(int radius)
+   {
+      this.radius = radius;
+   }
+
+   /**
+    * Get the color of the fog to render.
+    *
+    * @return the color of the fog to render
+    **/
+   public int getColor()
+   {
+      return color;
+   }
+
+   /**
+    * Set the color of the fog to render.
+    *
+    * @param color color of the fog to render
+    **/
+   public void setColor(int color)
+   {
+      this.color = color;
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/view/render/RenderGeometryInstruction.java b/server/scs/ws/view/render/RenderGeometryInstruction.java
new file mode 100644
index 0000000..b9184d3
--- /dev/null
+++ b/server/scs/ws/view/render/RenderGeometryInstruction.java
@@ -0,0 +1,33 @@
+package psl.chime4.server.scs.ws.view.render;
+
+/**
+ * Renders an arbitrary geometry instruction on the screen.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class RenderGeometryInstruction extends RenderInstruction
+{
+   /** the geometry to render **/
+   private Geometry geometry;
+
+   /**
+    * Get the geometry that must be rendered.
+    *
+    * @return geometry to render
+    **/
+   public Geometry getGeometry()
+   {
+      return geometry;
+   }
+
+   /**
+    * Set the geometry to render.
+    *
+    * @param geometry Geometry to render
+    **/
+   public void setGeometry(Geometry geometry)
+   {
+      this.geometry = geometry;
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/view/render/RenderInstruction.java b/server/scs/ws/view/render/RenderInstruction.java
new file mode 100644
index 0000000..0c52d64
--- /dev/null
+++ b/server/scs/ws/view/render/RenderInstruction.java
@@ -0,0 +1,39 @@
+package psl.chime4.server.scs.ws.view.render;
+
+import psl.chime4.server.scs.ws.view.*;
+import psl.chime4.server.scs.persist.*;
+
+/**
+ * Represents an instruction to a 3D engine on how to draw something.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public abstract class RenderInstruction extends PersistentObject
+{
+   /** numeric code for this instruction **/
+   protected int instructionCode;
+
+   /** unique uri defining this instruction **/
+   protected String instructionURI;
+
+   /**
+    * Return the numeric code for this drawing instruction.
+    *
+    * @return numeric code for this drawing instruction
+    **/
+   public int getInstructionCode()
+   {
+      return instructionCode;
+   }
+
+   /**
+    * Get the URI that defines this instruction.
+    *
+    * @return uri defining this instruction
+    **/
+   public String getInstructionURI()
+   {
+      return instructionURI;
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/view/render/RenderInstructionChain.java b/server/scs/ws/view/render/RenderInstructionChain.java
new file mode 100644
index 0000000..8afa3d2
--- /dev/null
+++ b/server/scs/ws/view/render/RenderInstructionChain.java
@@ -0,0 +1,45 @@
+package psl.chime4.server.scs.ws.view.render;
+
+import java.util.*;
+
+/**
+ * Represents a collection of RenderInstructions chained together.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class RenderInstructionChain extends RenderInstruction
+{
+   /** list to store the render instructions in **/
+   private ArrayList chainList = new ArrayList(5);
+
+   public RenderInstructionChain()
+   {
+      super.instructionCode = RenderConstants.RENDER_INSTRUCTION_CHAIN;
+      super.instructionURI = RenderConstants.RENDER_INSTRUCTION_CHAIN_URI;
+   }
+
+   /**
+    * Add a RenderInstruction to the chain.
+    *
+    * @param ri render instruction to add to the chain
+    **/
+   public void addInstruction(RenderInstruction ri)
+   {
+      if (ri != null)
+      {
+         chainList.add(ri);
+      }
+   }
+
+   /**
+    * Return an iterator over all the render instructions in the chain.
+    *
+    * @return Iterator over all the render instructions in the chain
+    **/
+   public Iterator instructions()
+   {
+      chainList.trimToSize();
+      return chainList.iterator();
+   }
+}
diff --git a/server/scs/ws/view/render/RenderLightInstruction.java b/server/scs/ws/view/render/RenderLightInstruction.java
new file mode 100644
index 0000000..d5c17e0
--- /dev/null
+++ b/server/scs/ws/view/render/RenderLightInstruction.java
@@ -0,0 +1,169 @@
+package psl.chime4.server.scs.ws.view.render;
+
+/**
+ * Tells the 3D Renderer to draw a light.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class RenderLightInstruction extends RenderInstruction
+{
+   /** the intensity of the light **/
+   private float intensity;
+
+   /** vector defining the direction of the light **/
+   private float xOri;
+   private float yOri;
+   private float zOri;
+
+   /** the radius of the spotlight **/
+   private int radius;
+
+   /** the color of the light **/
+   private int color;
+
+   /** defines the type of light **/
+   private int lightType;
+
+   /** constants defining the type of light **/
+   public static final int POINT = 0;
+   public static final int RAY = 1;
+   public static final int SPOTLIGHT = 2;
+
+   public RenderLightInstruction()
+   {
+      super.instructionCode = RenderConstants.RENDER_LIGHT;
+      super.instructionURI = RenderConstants.RENDER_LIGHT_URI;
+   }
+
+   /**
+    * Get the intensity of the light to render.
+    *
+    * @return intensity of the light to render
+    **/
+   public float getIntensity()
+   {
+      return intensity;
+   }
+
+   /**
+    * Set the intensity of the light to render.
+    *
+    * @param intensity intensity of the light to render
+    **/
+   public void setIntensity(float intensity)
+   {
+      this.intensity = intensity;
+   }
+
+   /**
+    * Get the x-orientation of the light if it is a ray or spotlight.
+    *
+    * @return the x-orientation of the light if it's a ray or spotlight
+    **/
+   public float getXOrientation()
+   {
+      return xOri;
+   }
+
+   /**
+    * Get the y-orientation of the light if it is ray or spotlight.
+    *
+    * @return the y-orientation of the light source
+    **/
+   public float getYOrientation()
+   {
+      return yOri;
+   }
+
+   /**
+    * Get the z-orientation of the light source.
+    *
+    * @return the z-orientation of the light source
+    **/
+   public float getZOrientation()
+   {
+      return zOri;
+   }
+
+   /**
+    * Set the orientation of the light.
+    *
+    * @param xOri x-orientation of the light
+    * @param yOri y-orientation of the light
+    * @param zOri z-orientation of the light
+    **/
+   public void setOrientation(float xOri, float yOri, float zOri)
+   {
+      this.xOri = xOri;
+      this.yOri = yOri;
+      this.zOri = zOri;
+   }
+
+   /**
+    * Get the radius of the light.
+    *
+    * @return radius of the light
+    **/
+   public float getRadius()
+   {
+      return radius;
+   }
+
+   /**
+    * Set the radius of the light. If the light is a spotlight this is the
+    * rate of increase in the spotlight area, if it's a ray it's the radius
+    * of the ray.
+    *
+    * @param radian radius of the light in radians
+    **/
+   public void setRadius(int radius)
+   {
+      this.radius = radius;
+   }
+
+   /**
+    * Get the color of the light.
+    *
+    * @return the color of the light
+    **/
+   public int getColor()
+   {
+      return color;
+   }
+
+   /**
+    * Set the color of the light.
+    *
+    * @param color of the light
+    **/
+   public void setColor(int color)
+   {
+      this.color = color;
+   }
+
+   /**
+    * Return the type of light this is. Must be one of the predefined
+    * constants.
+    *
+    * @return the type of light
+    **/
+   public int getLightType()
+   {
+      return lightType;
+   }
+
+   /**
+    * Set the type of light to be rendered. Must be one of the predefined
+    * constants.
+    *
+    * @param lightType type of light to be drawn
+    * @throws IllegalArgumentException
+    *         if <code>lightType</code> is not one of the pre-defined types
+    **/
+   public void setLightType(int lightType)
+   {
+      this.lightType = lightType;
+   }
+}
+
\ No newline at end of file
diff --git a/server/scs/ws/view/render/RenderModelInstruction.java b/server/scs/ws/view/render/RenderModelInstruction.java
new file mode 100644
index 0000000..dfaa9c0
--- /dev/null
+++ b/server/scs/ws/view/render/RenderModelInstruction.java
@@ -0,0 +1,41 @@
+package psl.chime4.server.scs.ws.view.render;
+
+import psl.chime4.server.scs.ws.view.image.*;
+
+/**
+ * Tells the 3D Renderer to draw a model at the given context.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class RenderModelInstruction extends RenderInstruction
+{
+   /** the image to render **/
+   private ImageInfo image;
+
+   public RenderModelInstruction()
+   {
+      super.instructionCode = RenderConstants.RENDER_MODEL;
+      super.instructionURI = RenderConstants.RENDER_MODEL_URI;
+   }
+
+   /**
+    * Get the model to render.
+    *
+    * @return info about the model to render
+    **/
+   public ImageInfo getImage()
+   {
+      return image;
+   }
+
+   /**
+    * Set the information about the model to render.
+    *
+    * @param image info about the model to render
+    **/
+   public void setImage(ImageInfo image)
+   {
+      this.image = image;
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/view/render/RenderRotationInstruction.java b/server/scs/ws/view/render/RenderRotationInstruction.java
new file mode 100644
index 0000000..ccec25f
--- /dev/null
+++ b/server/scs/ws/view/render/RenderRotationInstruction.java
@@ -0,0 +1,39 @@
+package psl.chime4.server.scs.ws.view.render;
+
+/**
+ * Tells the renderer to rotate the current context.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class RenderRotationInstruction extends RenderInstruction
+{
+   /** angle to perform the rotation about **/
+   private float angleOfRotation;
+
+   public RenderRotationInstruction()
+   {
+      super.instructionCode = RenderConstants.RENDER_ROTATION;
+      super.instructionURI = RenderConstants.RENDER_ROTATION_URI;
+   }
+
+   /**
+    * Get the angle of the rotation to perform.
+    *
+    * @return angle of rotation to perform in radians
+    **/
+   public float getRotationAngle()
+   {
+      return angleOfRotation;
+   }
+
+   /**
+    * Set the angle of the rotation to perform.
+    *
+    * @param angle angle of rotation to perform
+    **/
+   public void setRotationAngle(float angle)
+   {
+      this.angleOfRotation = angle;
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/view/render/RenderScalingInstruction.java b/server/scs/ws/view/render/RenderScalingInstruction.java
new file mode 100644
index 0000000..cf7ac09
--- /dev/null
+++ b/server/scs/ws/view/render/RenderScalingInstruction.java
@@ -0,0 +1,69 @@
+package psl.chime4.server.scs.ws.view.render;
+
+/**
+ * Tells the 3D Renderer to perform a scaling instruction.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class RenderScalingInstruction extends RenderInstruction
+{
+   /** the scaling in the x-direction **/
+   private float xFactor;
+
+   /** the scaling of the y-direction **/
+   private float yFactor;
+
+   /** the scaling in the z-direction **/
+   private float zFactor;
+
+   public RenderScalingInstruction()
+   {
+      super.instructionCode = RenderConstants.RENDER_SCALING;
+      super.instructionURI = RenderConstants.RENDER_SCALING_URI;
+   }
+
+   /**
+    * Get the scaling factor in the x direction.
+    *
+    * @return scaling factor in the x direction
+    **/
+   public float getXFactor()
+   {
+      return xFactor;
+   }
+
+   /**
+    * Get the scaling factor in the y direction.
+    *
+    * @return scaling factor in the y direction
+    **/
+   public float getYFactor()
+   {
+      return yFactor;
+   }
+
+   /**
+    * Get the scaling factor in the z-direction.
+    *
+    * @return scaling factor in the z direction
+    **/
+   public float getZFactor()
+   {
+      return zFactor;
+   }
+
+   /**
+    * Set the factors to perform the scaling operation by.
+    *
+    * @param xFac factor to scale by x-wise
+    * @param yFac factor to scale by y-wise
+    * @param zFac factor yo scale by z-wise
+    **/
+   public void setScalingFactors(float xFac, float yFac, float zFac)
+   {
+      this.xFactor = xFac;
+      this.yFactor = yFac;
+      this.zFactor = zFac;
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/view/render/RenderSoundInstruction.java b/server/scs/ws/view/render/RenderSoundInstruction.java
new file mode 100644
index 0000000..a85f132
--- /dev/null
+++ b/server/scs/ws/view/render/RenderSoundInstruction.java
@@ -0,0 +1,89 @@
+package psl.chime4.server.scs.ws.view.render;
+
+/**
+ * Tells the 3D renderer to play a spatial sound.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class RenderSoundInstruction extends RenderInstruction
+{
+   /** URI of the sound file to play **/
+   private String sound;
+
+   /** vector indicating the direction of the sound **/
+   private float xOri;
+   private float yOri;
+   private float zOri;
+
+   public RenderSoundInstruction()
+   {
+      super.instructionCode = RenderConstants.RENDER_SOUND;
+      super.instructionURI = RenderConstants.RENDER_SOUND_URI;
+   }
+
+   /**
+    * Get the URI of the sound to play.
+    *
+    * @return uri of the sound to play
+    **/
+   public String getSound()
+   {
+      return sound;
+   }
+
+   /**
+    * Set the URI of the sound to play.
+    *
+    * @param sound uri of the sound to play
+    **/
+   public void setSound(String sound)
+   {
+      this.sound = sound;
+   }
+
+   /**
+    * Get the x-orientation to play the sound in.
+    *
+    * @return x-orientation to play the sound in
+    **/
+   public float getXOrientation()
+   {
+      return xOri;
+   }
+
+   /**
+    * Get the y-orientation to play the sound in.
+    *
+    * @return y-orientation to play the sound in
+    **/
+   public float getYOrientation()
+   {
+      return yOri;
+   }
+
+   /**
+    * Get the z-orientation to play the sound in.
+    *
+    * @return z-orientation to play the sound in
+    **/
+   public float getZOrientation()
+   {
+      return zOri;
+   }
+
+   /**
+    * Set the orientation of the sound. This is the general direction it will
+    * play in the current 3D context.
+    *
+    * @param xOri orientation in the x-dir
+    * @param yOri orientation in the y-dir
+    * @param zOri orientation in the z-dir
+    **/
+   public void setOrientation(float xOri, float yOri, float zOri)
+   {
+      this.xOri = xOri;
+      this.yOri = yOri;
+      this.zOri = zOri;
+   }
+}
diff --git a/server/scs/ws/view/render/RenderSpeechInstruction.java b/server/scs/ws/view/render/RenderSpeechInstruction.java
new file mode 100644
index 0000000..facd3ad
--- /dev/null
+++ b/server/scs/ws/view/render/RenderSpeechInstruction.java
@@ -0,0 +1,89 @@
+package psl.chime4.server.scs.ws.view.render;
+
+/*
+ * Tells the 3D renderer--if it can--to render a speech sound from the current
+ * context.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class RenderSpeechInstruction extends RenderInstruction
+{
+   /** text to say **/
+   private String text;
+
+   /** orientation to render the speech in **/
+   private float xOri;
+   private float yOri;
+   private float zOri;
+
+   public RenderSpeechInstruction()
+   {
+      super.instructionCode = RenderConstants.RENDER_SPEECH;
+      super.instructionURI = RenderConstants.RENDER_SPEECH_URI;
+   }
+
+   /**
+    * Get the text to say.
+    *
+    * @return text to say
+    **/
+   public String getText()
+   {
+      return text;
+   }
+
+   /**
+    * Set the text to say
+    *
+    * @param text text to say
+    **/
+   public void setText(String text)
+   {
+      this.text = text;
+   }
+
+   /**
+    * Get the x-orientation to render the speech in.
+    *
+    * @return x-orientation to render the speech in
+    **/
+   public float getXOrientation()
+   {
+      return xOri;
+   }
+
+   /**
+    * Set the y-orientation to render the speech in.
+    *
+    * @return y-orientation to render the speech in
+    **/
+   public float getYOrientation()
+   {
+      return yOri;
+   }
+
+   /**
+    * Get the z-orientation to render the speech in.
+    *
+    * @return z-orientation to render the speech in
+    **/
+   public float getZOrientation()
+   {
+      return zOri;
+   }
+
+   /**
+    * Set the orientation to render the speech in.
+    *
+    * @param xOri x-orientation to render the speech in
+    * @param yOri y-orientation to render the speech in
+    * @param zOri z-orientation to render the speech in
+    **/
+   public void setOrientation(float xOri, float yOri, float zOri)
+   {
+      this.xOri = xOri;
+      this.yOri = yOri;
+      this.zOri = zOri;
+   }
+}
diff --git a/server/scs/ws/view/render/RenderTextureInstruction.java b/server/scs/ws/view/render/RenderTextureInstruction.java
new file mode 100644
index 0000000..26dec89
--- /dev/null
+++ b/server/scs/ws/view/render/RenderTextureInstruction.java
@@ -0,0 +1,41 @@
+package psl.chime4.server.scs.ws.view.render;
+
+import psl.chime4.server.scs.ws.view.image.*;
+
+/**
+ * Renders a texture on some object.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class RenderTextureInstruction extends RenderInstruction
+{
+   /** ImageInfo object that describes the texture to render **/
+   private ImageInfo texture;
+
+   public RenderTextureInstruction()
+   {
+      super.instructionCode = RenderConstants.RENDER_TEXTURE;
+      super.instructionURI = RenderConstants.RENDER_TEXTURE_URI;
+   }
+
+   /**
+    * Get information about the image for the texture to render.
+    *
+    * @return info about the image for the texture to render
+    **/
+   public ImageInfo getTexture()
+   {
+      return texture;
+   }
+
+   /**
+    * Set information about the image for the texture to render.
+    *
+    * @param info info about the image of the texture to render
+    **/
+   public void setTexture(ImageInfo info)
+   {
+      this.texture = info;
+   }
+}
\ No newline at end of file
diff --git a/server/scs/ws/view/render/RenderTranslationInstruction.java b/server/scs/ws/view/render/RenderTranslationInstruction.java
new file mode 100644
index 0000000..483f79d
--- /dev/null
+++ b/server/scs/ws/view/render/RenderTranslationInstruction.java
@@ -0,0 +1,69 @@
+package psl.chime4.server.scs.ws.view.render;
+
+/**
+ * Tells the 3D renderer to change its rendering point.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class RenderTranslationInstruction extends RenderInstruction
+{
+   /** change in x location **/
+   private int xChange;
+
+   /** change in y location **/
+   private int yChange;
+
+   /** change in the z location **/
+   private int zChange;
+
+   public RenderTranslationInstruction()
+   {
+      super.instructionCode = RenderConstants.RENDER_TRANSLATION;
+      super.instructionURI = RenderConstants.RENDER_TRANSLATION_URI;
+   }
+
+   /**
+    * Get the change in the x-direction
+    *
+    * @return change in the x-direction
+    **/
+   public int getXChange()
+   {
+      return xChange;
+   }
+
+   /**
+    * Get the change in the y-direction
+    *
+    * @return change in the y-direction
+    **/
+   public int getYChange()
+   {
+      return yChange;
+   }
+
+   /**
+    * Get the change in the z-direction
+    *
+    * @return change in the z-direction
+    **/
+   public int getZChange()
+   {
+      return zChange;
+   }
+
+   /**
+    * Set the change to make the translation by.
+    *
+    * @param xChange change in the x-axis
+    * @param yChange change in the y-axis
+    * @param zChange change in the z-axis
+    **/
+   public void setChange(int xChange, int yChange, int zChange)
+   {
+      this.xChange = xChange;
+      this.yChange = yChange;
+      this.zChange = zChange;
+   }
+}
diff --git a/server/scs/ws/view/render/SphereGeometry.java b/server/scs/ws/view/render/SphereGeometry.java
new file mode 100644
index 0000000..f431253
--- /dev/null
+++ b/server/scs/ws/view/render/SphereGeometry.java
@@ -0,0 +1,38 @@
+package psl.chime4.server.scs.ws.view.render;
+
+/**
+ * Represents the geometry of a sphere.
+ *
+ * @author Azubuko Obele
+ * @version 0.1
+ **/
+public class SphereGeometry extends Geometry
+{
+   private float radius;
+
+   public SphereGeometry()
+   {
+      super.geomCode = RenderConstants.SPHERE_GEOMETRY;
+      super.geomURI = RenderConstants.SPHERE_GEOMETRY_URI;
+   }
+
+   /**
+    * Get the radius of the sphere.
+    *
+    * @return radius of the sphere.
+    **/
+   public float getRadius()
+   {
+      return radius;
+   }
+
+   /**
+    * Set the radius of the sphere.
+    *
+    * @param radius radius of the spehre
+    **/
+   public void setRadius(float radius)
+   {
+      this.radius = radius;
+   }
+}
\ No newline at end of file