Programmer’s
Manual – Shared Applications
This manual provides a guide for developers who are
interested in creating shared applications for the Access Grid. It gives an
overview of the shared application infrastructure currently available in the
toolkit and step-by-step instructions on how to build an application. In
addition, this document describes how to package and install an application to
make it available in Venue Clients. The
Access Grid Team highly encourages developers to build shared applications and
this manual provides necessary information to successfully implement the task.
A shared application is a piece of software that enhances
collaboration, where two or more people are allowed to view, modify, and add
information simultaneously. The Access
Grid Toolkit supports parallel collaborative work electronically with several
shared applications included in the software, for instance, the Shared Browser
and the Shared Presentation viewer. But more important, the Access Grid Toolkit
can be extended to include shared plug-in applications created by any
developer.
The information contained in
this manual gives developers guidelines on how to create shared applications
for the Access Grid. It outlines the overall system architecture as well as
detailed instructions on how to develop, package, and install an application.
Furthermore, developers will find the Application Monitor helpful when
debugging shared applications. The last section of this manual explains how to
use the monitor.
In order to support shared applications, an
Application Factory is present in the Venue. When an application session is
started, the Application Factory creates an Event Channel used for sending messages between Application Clients. It also starts a Web
service for the application object in the Venue, the Application Service, used for client registration and storage of
necessary state information. The
Event Channel and the Application Service enable the Venue to provide a
mechanism for discovery, coherence, and synchronization among application
clients. Figure 1 shows an overview of the system.
Figure 1 Shared Application - System Overview
The Access
Grid Toolkit provides developers with a Shared Application Client, implemented
in the SharedAppClient class, which should be used as a client-side object when
creating shared applications. The class interface includes methods for all
necessary client operations and by creating a SharedAppClient instance your
application can invoke methods that will access the Event Channel and the
Application Service. The architecture is described in Figure 2.
Figure 2
Shared
Application Client - Architecture
Create a shared application client. Use the client as
an interface to the application service and event channel provided by the
application session.
Parameters
Name The name of the application. Log files will by
default be named <appName>.log.
Create a connection to the Application Service at a specified
URL. The connection gives access to the Event Channel used for data
communication among application clients connected to the service.
Parameters
applicationURL Location of application service (https://localhost:8000/100).
clientProfile Your client profile.
Close all connections to the
Application Service and Event Channel.
Initialize the logging
mechanism.
Parameters
debugFlag If set to 1,
messages will be printed to file and command window.
logFile Name
of the log file. Defaults to name
specified in constructor.
Returns
logFile Log file to use for debug and error messages.
Register callback for event.
Several callbacks can be registered for each event.
Parameters
eventType Event
to listen for
callback Method invoked when receiving event of type eventType
Post an event to all
applications connected to the application service.
Parameters
eventType Event
to send.
data Information associated with the event of type eventType.
Set status associated with
this client.
Parameters
status Status string.
Set profile associated with this
client.
Parameters
Profile Your profile of type ClientProfile.
Add data to application
service.
Note:
If data with the same dataKey is already present in
the application service, the old dataValue will be
overwritten.
Parameters
dataKey Unique id for this data.
dataValue The
actual data.
Get data from application
service.
Parameters
dataKey Unique id of data.
Return a list of keys for
data present in application service.
Returns
[dataKeys] List of unique data IDs.
Return this client’s unique
identifier.
Returns
publicID Unique
identifier
Get participants of this
application session.
Note:
A participant is a client that joined this session with the clientProfile
parameter set.
Returns
[participantDescription]
List of ParticipantDescriptions.
Get components of this application session.
Note:
Every client that joined this session is considered a component.
Returns
[publicId] List of public IDs.
Get unique ID of application
service as represented in the Venue.
Returns
uniqueId Unique identifier for this service.
Get URL to Venue where this
application session is running.
Returns
url Venue
location (for example; https://localhost:8000/Venues/default)
Get application state
information.
Returns
{State} Dictionary
containing application state.
Note:
Keys for state dictionary are name, description, id, mimeType,
uri, and data.
A shared application typically includes information
that represents the state of the application session. The Application Service,
created in the Venue when a session starts, should be used for storing the
state data. Each client joining the session will then be able to load the data
and perform necessary updates. Also, to synchronize participants during the
application session, clients should send events to notify any changes they make
to the state.
To explain how to build a shared application, we use the
Shared Browser, currently available in the Access Grid software, as a reference
example throughout this section. In the Shared Browser case, the state data is
represented by the current URL. If a participant joins the session, the Shared
Browser retrieves the URL from the service and browses to the right Web page. If
the participant changes the URL, the Shared Browser sends an event message,
containing the new URL, to all participants and also changes the URL stored in
the service to the new Web location. When other clients receive the event, they
navigate their browser to the same URL and, hence, browse the Web together and
maintain a synchronized view of the shared state.
The following code includes the main implementation
of the Shared Browser. The application
is built using Python with its user interface developed in wxPython.
Please note that the user interface class is not included in the example code.
Following sections will provide a walk-through of the Shared Browser code
below.
from AccessGrid.SharedAppClient import
SharedAppClient
from AccessGrid.Platform.Config import
UserConfig
from AccessGrid.ClientProfile import
ClientProfile
1.
class SharedBrowser( wxApp ):
2.
"""
3.
The SharedBrowser
combines a SharedApplication and a WebBrowser
4.
to provide shared web browsing to venue participants.
5.
"""
6.
def OnInit(self):
7.
return 1
8.
def OnExit(self):
9.
'''
10. Shut down shared
browser.
11. '''
12. self.sharedAppClient.Shutdown()
13. os._exit(1)
14. def __init__(
self, appServiceUrl, debugMode
= 0, logFile = None):
15. '''
16. Creates the shared application client, used
for
17. application service interaction, and opens
a web browser
18. for UI display.
19. '''
20. wxApp.__init__(self,
False)
21. # Create shared application client.
22. self.sharedAppClient
= SharedAppClient("SharedBrowser")
23. self.log = self.sharedAppClient.InitLogging(debugMode,logFile)
24. # Get client profile.
25. try:
26. userConf = userConfig.instance().GetConfigDir()
27. cpFile = os.path.join(userConf,
"profile")
28. clientProfile
= ClientProfile(cpFile)
29. except:
30. log.exception("Failed to load profile.")
31. clientProfile
= None
32. # Join the application session.
33. self.sharedAppClient.Join(appServiceUrl, clientProfile)
34. # Register browse
event callback.
35. self.sharedAppClient.RegisterEventCallback("browse",
36. self.BrowseCallback)
37. # Create Browser Window
38. self.frame = wxFrame(None, -1, "Browser")
39. self.browser = WebBrowser(self.frame, -1, self.log, self.frame)
40. # Add callback for local browsing
41. self.browser.add_navigation_callback(self.IBrowseCallback)
42. # Browse to the current url,
if exists
43. currentUrl = self.sharedAppClient.GetData("url")
44. if len(currentUrl) > 0:
45. self.browser.navigate(currentUrl)
46.
self.sharedAppClient.SetParticipantStatus(currentUrl)
47. self.frame.Show(1)
48. self.SetTopWindow(self.frame)
49. def BrowseCallback(self, event):
50. '''
51.
Callback invoked when
incoming browse events arrive. Events
52.
can include this
component's browse events, so these need to
53.
be
filtered out.
54.
'''
55.
# Determine if the sender
of the event is this component.
56.
(senderId, url) = event.data
57.
if senderId == self.sharedAppClient.GetPublicId():
58.
self.log.debug("Ignoring"+url+"from myself ")
59.
else:
60.
self.log.debug("Browse
to "+ url)
61.
self.browser.navigate(url)
62.
self.sharedAppClient.SetParticipantStatus(url)
63. def IBrowseCallback(self, data):
64. '''
65. Callback invoked when local browse events
occur.
66. '''
67. # Send out the event, including our public
ID in the message.
68. publicId = self.sharedAppClient.GetPublicId()
69.
message = (publicId,
data)
70. self.sharedAppClient.SendEvent("browse",
message)
71. # Store the URL in the application service
in the venue.
72. self.sharedAppClient.SetData("url", data)
When you
develop a shared application, you should create a SharedAppClient
object to use for communication with the Application Service that is running in
the Venue and the Event Channel. The application name, “SharedBrowser”
in this example, is the name that identifies your application, and log files
will by default be named SharedBrowser.log. To
initialize logging, call the InitLogging method that
returns a handle to the log file.
21. # Create shared
application client
22. self.sharedAppClient
= SharedAppClient("SharedBrowser")
23. self.log
= self.sharedAppClient.InitLogging(debugMode,logFile)
The next step is to join the application session in
the Venue by using the Join method
in the SharedAppClient. The appServiceURL parameter should be provided as a
command line option to the application and will get loaded automatically when
the application is opened in the Venue Client (read section 5 for information
about packaging). The ClientProfile
argument is used to identify you in the application. For example, your name
will be displayed in the Application Monitor once you have joined a session
(see Section 8).
32. # Join the application
session.
33. self.sharedAppClient.Join(appServiceUrl, clientProfile)
You have now established a connection to the service
and are allowed to use the event channel and access service data.
Application clients are synchronized by exchanging
event messages containing reference data. To send an event message to other
application clients, you should use the SendEvent
method.
When a participant of the Shared Browser navigates to
a new URL, a tuple is sent as event data (publicId, data) associated with the “browse” event type.
The publicId is the unique ID of the sender of this
event, and data is the URL you wish to browse to. Of course, when writing an
application, you can decide the type of the data to send. It does not have to
be a tuple.
67. # Send out the
event, including our public ID in the message.
68. publicId
= self.sharedAppClient.GetPublicId()
69. message = (publicId, data)
70. self.sharedAppClient.SendEvent("browse", message)
In order to receive events, your application should
register event callbacks; methods that will be invoked when an event occurs.
Callbacks are registered with the RegisterEventCallback method of the SharedAppClient.
The method should have one parameter, the event
that includes the received message.
The Shared Browser registers only one callback, the BrowseCallback,
which is invoked when a “browse” event
type is received. The browse event message includes two pieces of data, senderId and url.
The senderId is the unique ID of the application
client that sent the message, and the url
is the address to which we should navigate our browser.
34. # Register browse event callback
35. self.sharedAppClient.RegisterEventCallback("browse",
36. self.BrowseCallback)
…
49. def BrowseCallback(self, event):
50. '''
51. Callback
invoked when incoming browse events arrive.
Events
52. can include this component's browse events, so these need to
53. be filtered out.
54.
'''
55. # Determine if
the sender of the event is this client.
56. (senderId,
url) = event.data
57. if senderId == self.sharedAppClient.GetPublicId():
58. self.log.debug("Ignoring"+url+"from myself ")
59. else:
60. self.log.debug("Browse
to "+ url)
61. self.browser.navigate(url)
62. self.sharedAppClient.SetParticipantStatus(url)
In order to synchronize clients, state information
should be stored in the Application Service. State values can be set by using
the SetData
method of the SharedAppClient. Each piece of
information is distinguished by the data key, in this example “url,” and
the actual data is contained in the data value, data.
71. # Store the
URL in the application service in the venue
72. self.sharedAppClient.SetData("url", data)
Application clients will join a session at different
times and have to load current state of the session in order to participate. When
your application needs to load current application state, you should use the GetData method of the SharedAppClient.
For the Shared Browser, the GetData method with key
set to “url”
will return the current url.
42. # Browse to
the current url, if exists
43. currentUrl
= self.sharedAppClient.GetData("url")
44. if len(currentUrl) > 0:
45. self.browser.navigate(currentUrl)
All clients joining the application session will
automatically, when calling the Join method, submit their client profile to the
service. The profile is used for monitoring purposes (see Application Monitor
in Section 8). Use the SetParticipantProfile
method to change your profile.
After joining an application session, a participant
will be assigned status “connected.” If you want additional status values to be
set, call the SetParticipantStatus
method in the SharedAppClient. In order to keep track
of which Web page each participant is currently viewing, the Shared Browser
uses the URL as the status parameter.
66. self.browser.navigate(url)
62. self.sharedAppClient.SetParticipantStatus(url)
It is critical that you exit the application session
properly. When closing down your client, call Shutdown to disconnect from the service.
8. def OnExit(self):
9.
'''
10. Shut down shared browser.
11.
'''
12. self.sharedAppClient.Shutdown()
13. os._exit(1)
To install the application and make it available in
Venue Clients, you must make sure that your program is packaged in a format recognized
by the Access Grid software. The easiest way is to create necessary files and
store them in a zip archive, but several different formats are supported
(described in Section 6).
In addition to program files containing the
application code, your package should include a <applicationName>.app
file describing the application.
Example - The SharedBrowser.app
file
[application]
name = Shared Browser
mimetype =
application/x-ag-shared-browser
extension = sharedbrowser
files = SharedBrowser.py
[commands]
Open = %(python)s
SharedBrowser.py
-a %(appUrl)s
name
Represents the application in the Venue. This name
will be added to the list of available applications under Venue – Start Application Session in the Venue Client.
mimetype
Type
associated with this application, recommended mime type is application/x-ag-<name>.
extension
File
extension associated with the mime type, recommended extension is <name>.
files
Program files containing the application code.
The commands listed in this section will show up in
the pop-up menu that appears when you right click the application session in
the Venue Client. Selecting Open, from the menu option in this
example, would execute the command %python
SharedBrowser.py -a <appUrl>.
The appUrl describes the location of the application
service created in the venue and is automatically substituted by the Access
Grid Toolkit during runtime.
Note: The Open
menu option is always the first item of the pop-up menu, illustrated in Figure
3. Therefore, make sure to include an
Open command in the application description file. Delete,
Open Monitor…, and Properties are
also permanent application options; however, no command should be specified for
these options in the application description file. Their execution is already
specified within the toolkit.
Figure 3 Menu Options for a Shared Application Session
.
Use the Access Grid Package Manager (AGPM) to
register the application with your user environment. Once registered, the
program will be available in the Venue Client under Venue – Start Application Session. The AGPM offers several ways of
locating the application:
agpm –f
<applicationName>.app
agpm –d
directory containing the <applicationName>.app
agpm –z zip
archive containing the <applicationName>.app
agpm –p
package archive containing the <applicationName>.app
For example, if the SharedBrowser.py
and SharedBrowser.app files are saved in a zip
archive in /home/<user>/SharedBrowser/SharedBrowser.zip,
you can install the application by running
$ agpm –z /home/<user>/SharedBrowser/SharedBrowser.zip
For more information about different options use
$ agpm –h
After installation is completed, your application
will be represented in the Venue – Start
Application Session menu of the Venue Client. Each participant will be able
to select that menu option and start a session of your shared application in
the Venue. To join, right click the session, and select Open.
The application monitor is a piece of software that
shows information about a specific application session. Displayed information
includes application name and data as well as participants and their current
status. Additionally, the event window prints all changes in application state;
see Figure 4.
Figure 4 Application Monitor
As a developer, you will find the Application Monitor
useful for debugging, as you can view state changes of the application session
in the window. To open the monitor, right click the session, and select Open Monitor in the Venue Client; see
Figure 5.
Figure 5 Open Application Monitor
Note: To be displayed properly in the Application Monitor,
make sure you join the application session with the client profile parameter
set.