View this PageEdit this PageAttachments to this PageHistory of this PageHomeRecent ChangesSearch the SwikiHelp Guide
Hotspots: Admin Pages | Turn-in Site |
Current Links: Cases Final Project Summer 2007

Team: Everyone Gets Paid

Welcome to our case page for CS2340 Spring 2005. First off I will briefly go over what we had to do to accomplish our project, then I will provide you with some good pointers on how to trick Squeak into doing what you (and the professor) want it to do. Since I wrote most of the networking code most of what I post will be network related, but I will also give some nice tricks for saving object state via XML.

Jeremy - Network Programmer & L33t Case Page Writer
Will - GUI/View Programmer
Duckett - DB
Nate - UML

The Project:

For the spring semester 2005 we were supposed to implement an air graffiti service (like the real one that made the CoC website a while back except muuuuuch lamer) for the desktop and for a PDA. Generally, our project was quick and painless. Two of us concentrated on design and two of us coded. Some screenshots of the final product:

Uploaded Image: l33t.jpg Uploaded Image: l33t2.jpg

It's a very simple interface. It's not flashy, but it always met the required functionality for each milestone.

So the Air Grafitti server is supposed to allow users to log on and leave notes in various locations for other people. A user should be able to search for notes within a certain radius in a location and then have a list of all the notes cooresponding to their username displayed. Designing this for a Desktop interface was really easy, but porting to the PDA posed some problems (which I will describe later). Milestones 1 and 2 were trivial prerequisites for the final product so I won't describe them.

Milestone 3

Design time. Since we were all but given a working server client pair (thanks Lex =) ) all we needed to do was design our protocol and our client model view. Lex's original networking example used a Morph as a server stepper but we planned on actually implementing a server view (see screenshots) for more control. The Morph worked fine for Milestone 2, but I was always having problems with non-terminated connection queues (see bug list) and I had no idea why. The class comment for our server describes our protocol. Note that the items with parenths around them are actually arrays of strings.

This is the main server for our location based service. When the server is initialized it will read in a list of
locations from an xml file called "locations.xml". If it cannot find this file, it will return an error and shut down.


Instance variable descriptions:
locations -> A list of all the locations that this server can currently support.
queue -> A ConnectonQueue that will handle new connections.
connections -> A list of all the currently attached to this server.
port -> The port that this server listens to.
After successfully starting up, it will listen on a default port for incoming connections. When the server receives a request
for a connection, it will accept the connection, create the user by parsing the login string and assign them a client ID. It
will then store that person in a dictionary using the client ID as the key and assign them the default location of NOWHERE.

Clients may communicate with the server by using the following protocol:

(LOGIN,userID,name,decription) - This message will be sent if a client wishes to log in. It will contain the name, description,
and the serialized map of the location.

(MOVE,userID,new location) - This message will change the users location and cause the server to sent an UPDT message to all
connected clients (or just clients within a location) so that they reflect the change.

(CHME,userID,new name,new description) - This message will change the users details and cause the server to send an UPDT message
to all connected clients so that they reflect the change.

(GTUSR,userID) - This message will tell the server to send back the details about a person.

(BYE,userID) - This message will be sent when a client wishes to log off. The server will shut down the socket associated with
the client.

The server may communicate with the clients by using the following commands:

(WELC,location list) - This message will signal to the client that the logon was successful.

(NUSR,serialized location object) - This message will be sent to all the clients in a location whenever a new user appears in
that location.

(NLOC,serialized location object) - This message will be sent to a client when it requests a location change.

(USRDAT,serialized person object) - This message will be received when the client requests user information.

(BYE,user ID) - The server will send this message to all clients to signify that the client with the supplied ID has logged of
or left the current location.

NOTE: Most of the code for this server was originally written by Lex Spoon. I just modified it to suite our purposes. ~jld

Milestone 4

Milestone 4 was interesting. We were forced to port our desktop app to the constrained resources of a HP IPAQ 5550. The port was semi-painless. All we had to do was rewire our view. Due to the way we designed our model/view interaction we had to change around 3 methods and the coding side of the project was finished. One big problem we ran into during this project was trying to get our PDA to connect to Tech's wireless network. We sat around for about an hour trying to figure it out then gave up and connected the PDA to Will's laptop and used the laptop's wireless. After getting the project to run on the PDA we had to perform a few minor GUI tweaks then we were finished. We had no problems with memory whatsoever, and the network ran decently fast. The most agitating part of this milestone (and prehaps the entire project) was exiting Squeak on the PDA without a custom world menu. It requires some skill.


The following additions were made to the protocol for milestone 4:


(NGET, location, user name) - Gets all the notes for a user at a specific location

(NADD, location, note object) - Gives a note to the server to add to some location.

(NREM, location, note, id) - Tells the server that the client wishes to delete a note at a specific location.
Note that the client has to send its ID along with the rest of the info. If the id doesnt match the creator or
recipient of the note then it cannot be deleted (this is a primitive form of security).

(NLIST, id) - Gets a list of all the notes on the server for the passed in id.

The following changes were made to the server for milestone 4:

1) Completely changed the view of the server. It is now controlled by a system window that will step the server
accordingly. This cuts down on the number of classes but does not add to the complexity of the system; instead it
made it much cleaner and easier to understand.

Milestone 5

This milestone was the bulk of the project for us. This is also the milestone where all the SUnit tests actually worked. SUnit was a continuing source of frustration for all of us. Either they didnt work correctly or we couldnt figure out how to test a certain aspect of a class (networking for instance). By the end of this milestone we had around 25 working SUnit cases that helped us track down a couple of bugs when we changed something (so yes, they are worth something). This milestone is where the server was upgraded to a SystemWindow instead of a Morph. This took care of the connection queue problem I mentioned earlier (due to cleaner code, not the fact that we were using a morph). I also had an extensive system of Transcript show: calls that were crucial to debugging the new server system.

Major Project Problems

Annoying Bug Number 1:
Occurance: Milestone 4
Environment: A standard Squeak image with Sixx XML serializer installed and the freaky eyeball mouse dead.
The Symptoms: After around 10 connections to the server from within the image the client would no longer connect to the server.
Debug Procedures and Resolution: After verifying via self halts and self inspects that the client was trying to connect to the correct port and net name I had a hunch that it was something to do with orphaned sockets remaining open with the client after getting a primitive failed exception. So after much cursing Squeaks name I loaded up a new image and filed in our changes. Everything worked fine again for around 10 or 11 connects, then I had the same problem. After retracing every line of client and server code I found that this bug was caused by my ignorance. I wasn't properly closing sockets so my code for pruning dead connections wasn't working. So I fixed that, loaded up a new image, and I ended up with the exact same problem AGAIN! At this point I want to take a sledgehammer to the States Machine I was working on, so I bit the bullet, forgot about the bug, and made sure we demo'd on a fresh image.

Return of Annoying Bug Number 1:
Occurance: Milestone 5
Environment: A standard Squeak image with Sixx SML serializer installed and the freaky eyeball mouse still dead.
The Symptoms: Still cant connect to the server more than 10 times.
Debug Procedures and Resolution: So ignoring a bug obviously wont make it go away. I rewrote our server to use a system window stepper instead of a morph stepper. This allowed me to control when the connection queue was shut down via a start and stop button. Im sure you can do this with an override to the delete method in morph, but for some reason that just wasn't working correctly for me. After properly setting up the SystemWindow to control my server everything worked fine. This bug was officially dead!

The #@$%^! Squeak is Broken Bug:
Occurance: Milestone 4 & 5
Environment: Our LocationViewer's TextMorphs.
The Symptoms: When hitting backspace inside a TextMorph Squeak randomly throws an Object not Indexable Error.
Debug Procedures and Resolution: This one, well, it kinda just went away. We think it's a problem within the Squeak environment (which is VERY moody anyways). We have no idea why this happens so we just ignored it. It never threw the error during demo so why bother.

How to trick Squeak into doing something useful

In this section I will describe a couple of techniques that really helped us during debugging (which was usually only about an hour of our meetings) and some other nice Squeak hacks.

General Debugging Tips:
Uploaded Image: menu.jpg

This gives you the option to look at the model or the view of the morph that you called it on. Both favorites.

Hacking Networking in Squeak:

Saving the State of Objects Using SIXX:

I stumbled upon this whilst tinkering with our M6. I needed a way to save and load the state of two lists called userAccts and Vendors so that those accounts persist after the server is shut down. So instead of thrashing through the DOM class and figuring out how to manually parse XML (for loading state), I figured why not use SIXX to do the dirty work for me? After all, it converts objects to XML as it is! So, heres a smidgeon of code to consider:

(FileStream isAFileNamed: 'usracts.xml') ifTrue: [
usrActsFile := FileStream fileNamed: 'usracts.xml'.
userAccts := Object readSixxFrom: (usrActsFile contentsOfEntireFile).
] ifFalse: [ userAccts := Set new. ].

This code will look for a file called usracts.xml in the Squeak root directory, and if it exists will load the last saved state of our userAccts list from that file! If the file doesnt exist, then theres nothing to load so it will simply create a new userAccts set. Neat huh? Now for the saving state case:

((userAccts notNil) and: [userAccts size > 0]) ifTrue: [
Transcript show: 'SERVER: Saving user accounts...'; cr.
usrActsFile := FileStream forceNewFileNamed: 'usracts.xml'.
usrActsFile nextPutAll: (userAccts sixxString).
usrActsFile close. ].

It couldn't be any easier! Oh, and remember this will only work if the file is created per example 2 and read in per example 1. Else SIXX will get confused.


Make sure you have SIXX filed in or the whole system wont work. If you're just downloading it to hack my server/client, inside LBSServ2 delete the the users, locations, and notes instance variables, delete the method categories 'other' and 'testing/debugging', delete the SUnit test class, change the initDebugMode class method, the processMessage:fromConnection: instance method, and the initialization instance method to fit your system and it should work. Do the same kind of thing to the client class and you are good to go.

Get the almighty SIXX here!

Link to this Page