Union Core Concepts
Union is a development platform for creating multiuser applications. It consists of three interoperating parts:
- Union Server
- Union Client Frameworks, such as Reactor and OrbiterMicro
- The UPC Protocol
Union Server is the communications hub of the platform, and the backbone of every deployed application. The server accepts inputs from all connected clients, passes messages between clients, and keeps clients synchronized with each other.
Union Client Frameworks are programming frameworks for creating Union client applications. For example, Reactor is a Union Client SDK for creating multiuser Adobe Flash applications.
The UPC Protocol is the language Union clients speak when communicating with the Union server. Many Union developers will never use UPC directly, but will encounter it in client and server log files that show messages moving back and forth between clients and the server.
Union breaks the complexity of multiuser application development down into a small group of digestible concepts:
- Clients
- Union Server
- Messages
- Rooms
- Attributes
- User Accounts
Clients
Each "client" is a single user of the multiuser system. Typically, a client is controlled by a real person who uses a "client application" to connect to the server, send input to the server, and receive updates in response. The client application provides the user's interface, which might include anything from a text area for chatting, to a whiteboard for shared drawing, to a gameplay area. A "client" can also be an automated program, such as a customer service bot that answers customer questions in a product-support application. Upon connection, each client is assigned an ID that is guaranteed to be unique for as long as the client is connected to the server. Clients can also register server-side user accounts in which to store user data that can be saved and retrieved across multiple connections, and accessed even when the client is offline.
Union Server
Union Server is the communications controller of the multiuser application. It is always running, waiting for clients to connect. Clients connect to the server over a "gateway," which is typically a persistent TCP/IP socket, but can theoretically be any end point that can send and receive messages in text or binary format (e.g., HTTP or UDP). Connected clients never communicate with each other directly. Instead, they send messages to the server and wait for the server to respond with a result or an update.
Messages
A "message" is a simple instruction with a name, arguments, a source, and a destination. For example, in a chat application, a message from clientA to clientB might have the name CHAT, an argument content with the value "hello", a source of clientA's client ID, and a destination of clientB's client ID. Messages can be filtered, so you can easily send a message to all clients with "green hair" or that are "on the red team" or have "over 25 sales this quarter". Think of messages as the "method calls" or "function calls" of the multiuser application.
Rooms
A "room" is a place for clients to engage in group communication. To become part of the group, clients "join" the room. The clients in a room are known as the "room's occupants." Group messages are sent to a room's occupants by addressing the room instead of a single client. For example, a Reactor client could send a message named "CHAT" to all occupants of a given room using the following code:
In the preceding code, theRoom is a reference to a Room object, "CHAT" is the message name, true means "echo the message to the sender if the sender is in the room," and "Union is fun!" is the message's first and only argument.
Clients can join more than one room at a time. A single client can play a game in one room while chatting in another and reviewing employee salaries at a managers' meeting in yet another.
By default, a client does not receive messages sent to rooms it is not in. However, clients can spectate the activity of a room by asking to "observe" it. A client observing a room is given all the same updates as the room's occupants, but does not appear in the room's occupant list. Observation is perfect for creating applications with spectation, such as people watching a game of chess or fans spectating a celebrity chat.
Rooms are useful on their own, but their true power comes with "room modules". A room module is a custom server-side script or Java class that adds new functionality to a room. For example, a room module might manage the progression of a live questionnaire at a conference. Or a module might implement the physics in a game of pong. Or send an email to a contest coordinator when a user wins a prize. Think of modules as the "brains" of a room.
Attributes
If "messages" are the "method calls" of a multiuser application, "attributes" are the variables. Attributes are used to keep track of data and share it among connected clients. Attributes can be defined by rooms, clients, and user accounts.
Room Attributes
When a room creates, sets, or removes an attribute, every client in the room is instantly notified (but clients that don't want the notification can opt out). For example, if a room named "weather_room" sets an attribute named "TEMPERATURE" to "32", then all occupants of "weather_room" will receive an update. In Reactor, clients register for room-attribute updates like this:
updateRoomAttributeListener);
This corresponding method handles the room-attribute change:
if (e.getChangedAttr().name == "TEMPERATURE" {
temperatureField.text = e.getChangedAttr().value;
}
}
Client Attributes
Client attributes come in two varieties: global and room-scoped. When a client creates, sets, or removes a global attribute, every client in every room containing the sender is instantly notified (again, clients can opt-out of the notification). When a client creates, sets, or removes a room-scoped attribute, only the occupants of the rooms specified by the attribute's scope are notified.
Here's the code you might use to set a global client attribute, "AGE", in a chat application:
The following code registers to be notified when a client attribute changes for any of the occupants of theRoom:
updateClientAttributeListener);
Finally, this code handles the "AGE" attribute change:
if (e.getChangedAttr().name == ChatAttributes.AGE) {
var newAge:String = e.getChangedAttr().value;
chatField.text.appendText("Client" + e.getClientID()
+ " has a new age: " + newName);
}
}
User Accounts
A Union user account gives a user a persistent identity on the server and a place to store information in a server-side data source. Users that have created an account and logged in can save account attributes permanently. Like client attributes, account attributes can be global or scoped to a room. When a user logs in, its global account attributes are automatically loaded. Room-scoped account attributes are automatically loaded as the user account's corresponding client joins or observes rooms.
Here's a little Reactor ActionScript code showing how to create and then login to a user account with the userID "ken" and the password "abc":
reactor.getAccountManager().login("ken", "abc");
By default, Union Server includes support for user accounts via a light-weight built-in database called Apache Derby. Because Derby is built-in to Union Server, Union's user-account features can be used without any special configuration or additional installation. However, developers who prefer to use another database or arbitrary data source can customize or fully replace Union's built-in database. For information on customizing Union's persistence data source, see Union Server Persistence.
Try Union!
Well, those are the basics. What's next? The best way to continue learning is to start making your own multiuser applications. There's already a free Union server for you to play with at tryunion.com. If you know ActionScript 3.0, you can go build Your First Union Application right now.
Happy coding!