Introduction
This part explains steps for providing multiply rooms to existent chat application.
Palace Chat
This type of chat is most difficult to implement. Extra attention should be applied to each detail. We need to decide how to divide users and messages by rooms. The first approach comes from relational theory - to each message and each session, we add a new field, which uniquely identifies a room. Or simply provide one-to-many relationships between the Rooms
table and Messages
table, Rooms
table and Sessions
table.
Figure 5 - Division data by rooms with relational theory
Although this approach will work with both XML and relational data stores, it is optimal for relational databases, but not for XML.
The second approach uses XML hierarchical nature. Here, an additional attribute with a foreign key is not required. Including a ROOM
node will provide a fast room data identification and access.
<ROOT>
<ROOM id=1 name="room 1 name">
<ITEM>Message body 1</ITEM>
<ITEM>Message body 2</ITEM>
</ROOM>
<ROOM id=2 name="room 2 name">
<ITEM>Message body 3</ITEM>
<ITEM>Message body 4</ITEM>
. . . . .
</ROOM>
</ROOT>
Sessions are divided by rooms using the same approach. For performance reasons, it is located in different XML documents. This scenario is faster by theory - searching of the room is performed only for a single level of hierarchy (ROOM). This is opposite to relational data querying, where each record identified is a room subset.
Applying this approach to existent chat logic requires provision of a new class. This class must behave the same way as SharedXML
class, but work with XML node specified in constructor. Its constructor prototype is SingleLevelXML(xmlNode)
. Most methods of SharedXML
class can be used in SingleLevelXML
class, with minimal changes. To reuse behavior, we need to point in class constructor, to already defined methods of SharedXML
class.
function SingleLevelXML(xmlNode) {
this.xmlNode = xmlNode;
this.getWorkingNode = SingleLevelXML_getWorkingNode;
this.xmlSection = "ITEM";
this.addNode = SharedXML_addNode;
this.insertNode = SharedXML_insertNode;
this.insertXmlNode = SharedXML_insertXmlNode;
this.findNode = SharedXML_findNode;
this.findNodeByName = SharedXML_findNodeByName;
this.removeNode = SharedXML_removeNode;
this.setAttribte = SharedXML_setAttribte;
this.getItems = SharedXML_getItems;
}
Method getXMLDocument()
must be replaced with getWorkingNode()
for both classes. This replacement is required for better code reuse. Class LimitedXML
needs the same changes.
To add multiple room features requires, at least, two new pages. These are roomslist.asp and newroom.asp. The first page provides the room selection to participate in and the number of active users in each room. The second page allows us to define a new room.
Roomslist.asp is referenced by the start page after successful login. This role leads to moving authorization and session creation routines to the roomslist.asp page. But which room does the user enter after logging in? To resolve this problem, we'll provide a temporary or hidden room. This room is only available for internal purposes, and users will be added to it when they have successfully logged in. After selecting a valid room, the session record is moved to an appropriate room node. The trick takes a green light for next two features: switching of room without re-login and opening a separate room.
Switching of rooms is performed in the same manner as entering to the chat: moving a session record. Opening a separate room leads to cloning a session, to be in another room node. In details, it looks like the "algorithm of three glasses".
Figure 5 - "Algorithm of three glasses"
The first two glasses are real rooms. The third glass is hidden room. In the current design, a user can't select a different room without exiting or opening a separate window. A hidden room can help here. It is simple to move or copy a user record to hidden room and represent an available rooms list. After a user selects one, the chat application behaves in the same way as when entering a room after login: user records moved from a hidden room to the target room.
function UserManager_switchRoom(roomIDOld, roomIDNew, sessionID) {
var previousRoom = this.getRoomSessions(roomIDOld);
var oldXmlNode = previousRoom.findNode(sessionID);
if(oldXmlNode != null) {
var targetRoom = this.getRoomSessions(roomIDNew);
var xmlNode = targetRoom.findNode(sessionID);
if(xmlNode == null) {
xmlNode = oldXmlNode.cloneNode(false);
targetRoom.insertXmlNode(xmlNode);
var newSession = new Session(xmlNode, true);
newSession.markLastAccessTime();
}
previousRoom.removeNode(oldXmlNode);
}
}
Application Setup
The article consists of four iterations, which are all working examples. These are:
- Simple chat (Samples\SimpleChat).
- User-friendly chat (Samples\UserFriendlyChat).
- Registrable chat (Samples\RegistrableChat).
- Palace chat (Samples\PalaceChat).
All four of these applications have a similar IIS installation process. In the IIS administration panel, define virtual directories for each required type of chat. Point them to the appropriate disk location for the sample, with the addition of the \XMLChat subfolder. For the Simple chat, it looks like this:
- Virtual Directory name: SimpleChat
- Content Directory: [Your local path]\Samples\SimpleChat\XMLChat\
Access permissions can be default: Read and Run scripts. Session state should be disabled for better performance.
Registrable Chat and Palace Chat also require folders with read-write permissions. They also require a DB folder, which is not a subfolder of the web application. For example: [Your local path]\Samples\SimpleChat\DB\.
After these steps have been completed, you are ready for browsing and trying to chat. If it does not work, you may need to install MS XML Parser 3.0 or higher on the server-side. It is shipped with IE 5.0 and later.
The chat settings can be customized in the INC/Settings.js file. Here is a list of the customizable functions:
getMessageRefreshTime()
- specifies amount of time, in seconds, for next messages history pane refresh.
getVisitorsRefreshTime()
- same as previous, but for active users pane.
getSessionExpirationTime()
- specifies time-out interval of disconnected user expiration, in seconds.
getMaxMessages()
- specifies maximum quantity of messages to represent for users.
getUsersDataPath()
- specifies disk location to store persistent users information.
getRoomsDataPath()
- same as previous, but for storing rooms information.
Suggested Enhancements
In this article, we described four increasingly sophisticated Chat applications, but, as with any other program, they can be upgraded even further. First, the administration for users and rooms can be enhanced. Another useful possibility is personal chat rooms, for two users only. To provide good design adaptability, a cascading style sheet (CSS) can be applied to each page.
The Registrable and Palace chats contain a limitation on the number of registered users. Because whole user registration store is loaded into memory by the XML parser, it cannot be larger than available physical memory size divided by ten. To avoid this problem, we can either increase the physical memory or provide a relational database to store users.
Conclusion
Here, we've provided a good set of chat applications: from simple to advanced. Each chat application is an improvement on the previous version.
For each type of chat, we've provided explanation of the most difficult details and some tricks. All four chat examples have been written using an Object-oriented approach (as it is possible with JavaScript). Extra attention was applied to performance aspects. All samples are complete and ready to integrate into real sites. All examples are tested with various browsers on different platforms:
- Windows: Internet Explorer versions (4, 5, 6), Netscape versions (4.7, 6, 7), Opera 6.
- Linux: Netscape 4.6.
- Mac: Netscape 4.7, Internet Explorer 5.0.