Sunteți pe pagina 1din 442

Front cover

Working with the Sametime Client Toolkits


Java, C++, COM and Sametime Links toolkits The Sametime Places architecture Many "real world" application samples

Sren Peter Nielsen Volker Jrgensen Rami Menashes Tony Patton Marjorie Schejter

ibm.com/redbooks

International Technical Support Organization Working with the Sametime Client Toolkits December 2002

SG24-6666-00

Take Note! Before using this information and the product it supports, be sure to read the general information in Notices on page xi.

First Edition (December 2002) This edition applies to Lotus Sametime 2.5 and Lotus Sametime 3.0.

Comments may be addressed to: IBM Corporation, International Technical Support Organization Dept. TQH Mail Station P099 2455 South Road Poughkeepsie, NY 12601-5400 When you send information to IBM, you grant IBM a non-exclusive right to use or distribute the information in any way it believes appropriate without incurring any obligation to you.

Copyright International Business Machines Corporation 2002. All rights reserved. Note to U.S Government Users Documentation related to restricted rights Use, duplication or disclosure is subject to restrictions set forth in GSA ADP Schedule Contract with IBM Corp.

Contents
Notices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi Trademarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xii Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii The team that wrote this redbook . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiv Comments welcome . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xvi Part 1. Introduction to Sametime client toolkits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Chapter 1. Introduction to Sametime. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.1 What is Sametime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.1.1 Community services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.1.2 Sametime Online Meeting services. . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.1.3 Sametime customization and integration services . . . . . . . . . . . . . . . 7 1.2 The Sametime client toolkits. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.2.1 The Sametime Links toolkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.2.2 The Sametime COM toolkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.2.3 The Sametime Java toolkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.2.4 The Sametime C++ toolkit. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.3 Which toolkit to use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.3.1 Target platform . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.3.2 Required features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.3.3 Initialization load time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 1.3.4 Programming skills . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 1.3.5 Toolkit comparison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.4 The structure of the book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 1.4.1 The Sametime Community Server Toolkit Redbook . . . . . . . . . . . . . 15 1.5 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Chapter 2. Sametime toolkit services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 2.1 Sametime architecture basics. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 2.1.1 Proxy objects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 2.1.2 The Model-View-Controller paradigm . . . . . . . . . . . . . . . . . . . . . . . . 20 2.1.3 Sametime events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 2.2 Interfaces and other funny words . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2.2.1 Event . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2.2.2 Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 2.2.3 Listener . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.2.4 Adapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

Copyright IBM Corp. 2002. All rights reserved.

iii

2.2.5 Extend and implement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.3 Sametime services: What can I do with them . . . . . . . . . . . . . . . . . . . 29 2.3.1 General features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 2.3.2 Community service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 2.3.3 Awareness service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.3.4 Places service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 2.3.5 Lookup service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 2.3.6 Instant messaging service. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 2.3.7 Token service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 2.3.8 Storage service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 2.3.9 Names service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 2.3.10 Directory service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 2.3.11 Post service. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 2.3.12 Meeting services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 2.3.13 Streamed media . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 2.4 The bare necessities for a client program . . . . . . . . . . . . . . . . . . . . . . 39 2.4.1 Create a Sametime session and load components. . . . . . . . . . . . . . 40 2.4.2 Login to the Sametime community . . . . . . . . . . . . . . . . . . . . . . . . . . 40 2.5 Core types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 2.5.1 Importing the core types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 2.5.2 Sametime ID types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 2.5.3 Sametime object types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 2.5.4 Sametime attribute types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 2.6 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 Chapter 3. Places architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 3.1 What can I do in a Place with the client toolkits . . . . . . . . . . . . . . . . . 50 3.2 Place-based awareness and collaboration . . . . . . . . . . . . . . . . . . . . . 51 3.3 The Sametime Places model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 3.3.1 Virtual places. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 3.3.2 Sections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 3.3.3 Activities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 3.3.4 Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 3.4 Communication in a place . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 3.5 Permissions list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 3.5.1 Access to the place and the stage section . . . . . . . . . . . . . . . . . . . . 56 3.5.2 Places span the community . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 3.5.3 Place scalability. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 3.6 The Places APIs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 3.7 Examples of doing things in a place . . . . . . . . . . . . . . . . . . . . . . . . . . 57 3.7.1 Entering a place and listening for place events. . . . . . . . . . . . . . . . . 58 3.7.2 Figuring out which section is which . . . . . . . . . . . . . . . . . . . . . . . . . . 60 3.7.3 Changing your section . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

iv

Working with the Sametime Client Toolkits

3.7.4 Getting your section and listening for section events . . . . . . . . . . . . 62 3.7.5 Getting a list of users in a section and listening to them . . . . . . . . . . 63 3.7.6 Setting attributes of place, section, user . . . . . . . . . . . . . . . . . . . . . . 64 3.7.7 Listening for changed attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 3.7.8 Sending messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 3.7.9 Listening for messages sent to you. . . . . . . . . . . . . . . . . . . . . . . . . . 67 3.8 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 Part 2. Java toolkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 Chapter 4. Installation and setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 4.1 Installing the toolkit package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 4.2 Installing the IBM JDK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 4.2.1 Setting up the path and classpath variables . . . . . . . . . . . . . . . . . . . 74 4.2.2 Compiling and running a JDK sample . . . . . . . . . . . . . . . . . . . . . . . . 76 4.2.3 Compiling and running a toolkit sample with the JDK . . . . . . . . . . . . 76 4.3 Setup of IBM VisualAge for Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 4.3.1 Importing the Sametime toolkit files into a project. . . . . . . . . . . . . . . 79 4.3.2 Setting up the classpath in VisualAge . . . . . . . . . . . . . . . . . . . . . . . . 82 4.3.3 Passing parameters to the applet . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 4.3.4 Modifying the java.policy file in VisualAge for Java. . . . . . . . . . . . . . 85 4.3.5 Running the applet within VisualAge. . . . . . . . . . . . . . . . . . . . . . . . . 86 4.3.6 Exporting the applet from VisualAge . . . . . . . . . . . . . . . . . . . . . . . . . 86 4.3.7 The resource not found problem. . . . . . . . . . . . . . . . . . . . . . . . . . . 87 4.4 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 Chapter 5. Introduction to Sametime Java applets . . . . . . . . . . . . . . . . . . 89 5.1 Sametime applet basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 5.1.1 QuickStart Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 5.1.2 init() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 5.1.3 start() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 5.1.4 stop() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 5.1.5 destroy() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 5.1.6 Using the LoginListener interface . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 5.2 Entering a place . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 5.2.1 STError: If something goes wrong . . . . . . . . . . . . . . . . . . . . . . . . . . 98 5.3 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 Chapter 6. A place-based auction example . . . . . . . . . . . . . . . . . . . . . . . 101 6.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 6.2 Objects in the application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 6.3 Application flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 6.3.1 Initialization of the auction by the auctioneer . . . . . . . . . . . . . . . . . 107 6.3.2 Entering as bidder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108

Contents

6.3.3 Entering as on-looker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 6.3.4 Bidding on an item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 6.3.5 Calling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 6.4 Client applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 6.4.1 The auctioneers application at a glance . . . . . . . . . . . . . . . . . . . . . 111 6.4.2 The customers application at a glance . . . . . . . . . . . . . . . . . . . . . . 113 6.5 The implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 6.5.1 Sametime services used . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 6.5.2 Class diagram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 6.5.3 Looking at the code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 6.5.4 Launching and passing parameters to the applets . . . . . . . . . . . . . 122 6.6 Event flows. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 6.7 Leveraging the places architecture . . . . . . . . . . . . . . . . . . . . . . . . . . 127 6.7.1 Sending text and data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 6.7.2 Changing attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 6.7.3 Receiving events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 6.7.4 Organizing messages, events, attributes . . . . . . . . . . . . . . . . . . . . 132 6.7.5 Other considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 6.8 What is next . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 6.9 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 Chapter 7. Customized chat UI applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 7.1 Customized ChatUI Example 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 7.2 Important classes in the sample . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 7.3 CustomizeChatFactory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 7.3.1 Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 7.3.2 CustomizeChatFactory2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 7.4 CustomizeChatUI2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 7.4.1 Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 7.4.2 CustomizeChatUI2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 7.5 ImagePanel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160 7.5.1 Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160 7.5.2 ImagePanel.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 7.5.3 The HTML file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 7.6 Deployment considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 7.6.1 Integrating with a Domino application . . . . . . . . . . . . . . . . . . . . . . . 164 7.6.2 Loading the logo from a jar file . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 7.7 Extending the functionality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 7.7.1 RedStorageFrame.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 7.7.2 Changes in the factory class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 7.8 How to use with other toolkit UI elements . . . . . . . . . . . . . . . . . . . . . 182 7.9 Passing a token between applets . . . . . . . . . . . . . . . . . . . . . . . . . . . 183 7.9.1 JavaScript for accessing the token . . . . . . . . . . . . . . . . . . . . . . . . . 189

vi

Working with the Sametime Client Toolkits

7.9.2 The HTML form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 7.9.3 Sharing information with other applets . . . . . . . . . . . . . . . . . . . . . . 192 7.10 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 Part 3. C++ toolkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 Chapter 8. Working with the C++ toolkit . . . . . . . . . . . . . . . . . . . . . . . . . . 199 8.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 8.1.1 Modular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 8.1.2 Thread-safe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 8.1.3 Extendable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 8.1.4 Object-oriented API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 8.1.5 The toolkit services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 8.2 Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 8.2.1 The toolkit package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 8.2.2 Background information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 8.3 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206 Chapter 9. A complex meetings sample . . . . . . . . . . . . . . . . . . . . . . . . . . 207 9.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 9.2 Sample architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 9.2.1 The MeetingUI class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 9.2.2 The MeetingController class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 9.2.3 The NWayChatUIDlg class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 9.2.4 The MeetingLauncher class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 9.2.5 The InviteUIDlg class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230 9.2.6 The MeetingDlg class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 9.3 Preparing the MeetingUI class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 9.3.1 Initialize MeetingUI class. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 9.3.2 Calling MeetingUI API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 9.4 Four steps to create the meetings . . . . . . . . . . . . . . . . . . . . . . . . . . 242 9.4.1 The invitation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 9.4.2 The place . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264 9.4.3 Generating a token . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290 9.4.4 Launch Sametime meeting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292 9.5 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296 Chapter 10. Using the C++ toolkit in Win32 programs. . . . . . . . . . . . . . . 297 10.1 The Win32Status sample . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298 10.1.1 The sample code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298 10.1.2 The output window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 10.2 Writing Win32 code with Sametime C++ toolkit. . . . . . . . . . . . . . . . 304 10.2.1 Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304 10.2.2 Using wmain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304

Contents

vii

10.2.3 The message loop. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304 10.3 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305 Part 4. COM and Sametime Links toolkits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 Chapter 11. The COM toolkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 11.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310 11.2 Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312 11.2.1 Accessing the toolkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312 11.2.2 Installing the toolkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313 11.2.3 Adding the COM toolkit reference to your project . . . . . . . . . . . . . 313 11.3 Visual Basic samples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315 11.4 The Login sample . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316 11.4.1 Initialize Sametime services - the SametimeSession module . . . . 316 11.4.2 Login to Sametime - the LoginForm . . . . . . . . . . . . . . . . . . . . . . . 317 11.5 The Awareness sample . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320 11.5.1 Initialize Sametime service - the SametimeSession module. . . . . 321 11.5.2 Be aware of other users - the AwarenessForm. . . . . . . . . . . . . . . 323 11.5.3 Log into Sametime - the LoginForm . . . . . . . . . . . . . . . . . . . . . . . 332 11.5.4 Adding users to the AwarenessList - the AddUserForm . . . . . . . . 335 11.5.5 Changing my own status - the ChangeStatusForm . . . . . . . . . . . 338 11.6 The BuddyList sample . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342 11.6.1 Initialize Sametime service - the SametimeSession module. . . . . 343 11.6.2 Adding Instant Messaging capabilities - the BuddyListForm. . . . . 345 11.6.3 Chatting with others - the ChatForm . . . . . . . . . . . . . . . . . . . . . . . 348 11.7 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354 Chapter 12. The Sametime Links toolkit . . . . . . . . . . . . . . . . . . . . . . . . . . 355 12.1 Toolkit features. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356 12.1.1 Awareness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358 12.1.2 Instant messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358 12.1.3 Meetings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359 12.1.4 Set status . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359 12.1.5 Place-based awareness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360 12.1.6 Chat rooms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361 12.1.7 Advanced JavaScript API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362 12.2 Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363 12.2.1 Enabling a Web application. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363 12.2.2 Authentication considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364 12.2.3 Adding a Sametime link . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365 12.2.4 A simple online assistance sample . . . . . . . . . . . . . . . . . . . . . . . . 366 12.3 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368 Part 5. Appendixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369

viii

Working with the Sametime Client Toolkits

Appendix A. Some deployment considerations . . . . . . . . . . . . . . . . . . . . 371 Infrastructure for anonymous users . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371 Applet connections over the Internet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372 Instant messaging and data transfer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374 Appendix B. Working with the auction house sample material . . . . . . . 375 Installing the auction house sample . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376 Looking at the code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376 Scenario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379 Appendix C. Sample auction scenario . . . . . . . . . . . . . . . . . . . . . . . . . . . 381 The scenario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382 Preparation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382 Entrance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383 Auction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385 Appendix D. Sametime portlets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391 Authentication by token . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392 Using a Domino database as applet container. . . . . . . . . . . . . . . . . . . . . . . . 392 Opening the Java Sametime Connect client . . . . . . . . . . . . . . . . . . . . . . . . . 393 Place awareness portlet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397 PlaceAwarenessList applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401 Sample files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405 Appendix E. Additional Web material . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407 Locating the Web material . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408 Related publications . . . . . . . . . . . . . . . . . . . . . . IBM Redbooks . . . . . . . . . . . . . . . . . . . . . . . . . . . . Referenced Web sites . . . . . . . . . . . . . . . . . . . . . . How to get IBM Redbooks . . . . . . . . . . . . . . . . . . . IBM Redbooks collections . . . . . . . . . . . . . . . . . ...... ...... ...... ...... ...... ....... ....... ....... ....... ....... ...... ...... ...... ...... ...... . . . . . 409 409 409 410 411

Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413

Contents

ix

Working with the Sametime Client Toolkits

Notices
This information was developed for products and services offered in the U.S.A. IBM may not offer the products, services, or features discussed in this document in other countries. Consult your local IBM representative for information on the products and services currently available in your area. Any reference to an IBM product, program, or service is not intended to state or imply that only that IBM product, program, or service may be used. Any functionally equivalent product, program, or service that does not infringe any IBM intellectual property right may be used instead. However, it is the user's responsibility to evaluate and verify the operation of any non-IBM product, program, or service. IBM may have patents or pending patent applications covering subject matter described in this document. The furnishing of this document does not give you any license to these patents. You can send license inquiries, in writing, to: IBM Director of Licensing, IBM Corporation, North Castle Drive Armonk, NY 10504-1785 U.S.A. The following paragraph does not apply to the United Kingdom or any other country where such provisions are inconsistent with local law: INTERNATIONAL BUSINESS MACHINES CORPORATION PROVIDES THIS PUBLICATION "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Some states do not allow disclaimer of express or implied warranties in certain transactions, therefore, this statement may not apply to you. This information could include technical inaccuracies or typographical errors. Changes are periodically made to the information herein; these changes will be incorporated in new editions of the publication. IBM may make improvements and/or changes in the product(s) and/or the program(s) described in this publication at any time without notice. Any references in this information to non-IBM Web sites are provided for convenience only and do not in any manner serve as an endorsement of those Web sites. The materials at those Web sites are not part of the materials for this IBM product and use of those Web sites is at your own risk. IBM may use or distribute any of the information you supply in any way it believes appropriate without incurring any obligation to you. Information concerning non-IBM products was obtained from the suppliers of those products, their published announcements or other publicly available sources. IBM has not tested those products and cannot confirm the accuracy of performance, compatibility or any other claims related to non-IBM products. Questions on the capabilities of non-IBM products should be addressed to the suppliers of those products. This information contains examples of data and reports used in daily business operations. To illustrate them as completely as possible, the examples include the names of individuals, companies, brands, and products. All of these names are fictitious and any similarity to the names and addresses used by an actual business enterprise is entirely coincidental. COPYRIGHT LICENSE: This information contains sample application programs in source language, which illustrates programming techniques on various operating platforms. You may copy, modify, and distribute these sample programs in any form without payment to IBM, for the purposes of developing, using, marketing or distributing application programs conforming to the application programming interface for the operating platform for which the sample programs are written. These examples have not been thoroughly tested under all conditions. IBM, therefore, cannot guarantee or imply reliability, serviceability, or function of these programs. You may copy, modify, and distribute these sample programs in any form without payment to IBM for the purposes of developing, using, marketing, or distributing application programs conforming to IBM's application programming interfaces.

Copyright IBM Corp. 2002. All rights reserved.

xi

Trademarks
The following terms are trademarks of the International Business Machines Corporation in the United States, other countries, or both: IBM eServer Redbooks (logo) Everyplace IBM Perform Redbooks SP VisualAge WebSphere

The following terms are trademarks of International Business Machines Corporation and Lotus Development Corporation in the United States, other countries, or both: Domino Designer Domino iNotes Lotus Discovery Server Lotus Notes Lotus Notes QuickPlace Sametime Word Pro

The following terms are trademarks of other companies: ActionMedia, LANDesk, MMX, Pentium and ProShare are trademarks of Intel Corporation in the United States, other countries, or both. Microsoft, Windows, Windows NT, and the Windows logo are trademarks of Microsoft Corporation in the United States, other countries, or both. Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States, other countries, or both. UNIX is a registered trademark of The Open Group in the United States and other countries. C-bus is a trademark of Corollary, Inc. in the United States, other countries, or both. UNIX is a registered trademark of The Open Group in the United States and other countries. SET, SET Secure Electronic Transaction, and the SET Logo are trademarks owned by SET Secure Electronic Transaction LLC. Other company, product, and service names may be trademarks or service marks of others.

xii

Lotus Discovery Server 2.0

Preface
This IBM Redbook is for developers and architects who want to utilize Sametime functionality in applications based on Java, C++, COM, or HTML and JavaScript. We explore capabilities offered by the different Sametime client toolkits, which you can use to add functionality to existing applications, and to create powerful new applications that enable real-time collaboration. The book is divided into four parts plus appendices. In the first part we present an overview of the different client toolkits and discuss which can be used for various tasks. We go on to introduce the Sametime community services and the concepts of event-based programming. A special focus area for our redbook is virtual places managed by Sametime, so we describe the architecture of Sametime Places as well. In the second part we discuss the Java Toolkit in detail. We describe how to install and set up the toolkit, both with a Java Development Kit (JDK) and with IBM VisualAge for Java, and we show the minimum code required to get a Sametime applet to run. We then present a place-based sample where we explore how to implement an online bidding application, and discuss topics like different ways to communicate in a place, access control, and so on. We complete the Java discussion by looking at ways you can create your own chat window to be used by other toolkit components. We also discuss different ways to deploy Sametime applets and show integration with a Domino database. The third part deals with the Sametime C++ Toolkit. In the main sample we build a full-blown Sametime Connect client by extending the BasicBuddyList sample from the C++ Toolkit. One of the techniques shown is how to launch the Java-based Sametime meeting client from a C++ program. We also discuss the different requirements when using Microsoft Foundation Classes (MFC) or Win32 API for Sametime C++ programs in this part. The newest additions to the Sametime client toolkits are discussed in part four: the Sametime COM Toolkit and the Sametime Links Toolkit. The COM Toolkit allows you to Sametime-enable any application that supports Visual Basic for Applications (for example, Microsoft Windows). You can also write a complete Sametime application in Visual Basic, which we do in our sample. We develop a BuddyList application that shows how to use most of the functionality offered by the COM Toolkit.

Copyright IBM Corp. 2002. All rights reserved.

xiii

Sametime Links is a lightweight and easy-to-use toolkit. It is perfect for browser-based applications like e-commerce, CRM, help desk, and so on; and it does not require extensive programming skills. We give an overview of the toolkit and describe how easily it can add awareness and chat capability to an existing Web page. In the appendices we discuss some deployment considerations. We provide additional information about our online bidding sample, and we present two examples of Sametime portlets for WebSphere Portal Server. Most of the samples in this Redbook are available in source format from the IBM Redbooks Web site. Once you have read this book, we recommend that you explore what you can do with server-side Sametime programs in the redbook Working with the Sametime Community Server Toolkit, SG24-6667.

The team that wrote this redbook


This redbook was produced by a team of specialists from around the world working at the International Technical Support Organization, Poughkeepsie Center. Sren Peter Nielsen works for the International Technical Support Organization at Lotus Software - IBM Software Group, Cambridge, Massachusetts. He manages projects that produce redbooks about all areas of Lotus products. Before joining the ITSO in 1998, Sren worked as an IT Architect for IBM Global Services in Denmark, designing solutions for a wide range of industries. Sren is a Certified Lotus Professional at the Principal level in Application Development and System Administration. Volker Jrgensen works as a technical account manager for the Lotus software division of IBM, Stuttgart, Germany. In addition to his general technical presales role, he specializes in Sametime, supporting sales and services in Central Europe. Rami Menashes works for IBM Software Group at the IBM Haifa Software Lab in Rehovot, (Ubique) Israel. He specializes in C++, MFC, and COM applications and toolkit development. He has extensive experience with the Sametime C++ Connect Client, and has also worked on and developed the Sametime 2.x C++ Toolkit. Rami has also used his expertise in COM and OLE technology to develop the Sametime COM Toolkit.

xiv

Working with the Sametime Client Toolkits

Tony Patton is an application developer in Louisville, Kentucky. He has worked with Lotus Notes/Domino for over five years. Tony is the author of two books from Manning Publications: Domino Development With Java and Practical LotusScript. He is also a frequent contributor to industry publications. Marjorie Schejter works at the IBM Haifa Software Lab in Rehovot, (Ubique) Israel. She has over 15 years experience in the high tech industry. For the past several years she has specialized in the Sametime Toolkits, both as a technical writer and product manager. We want to extend a special thank you to the following people that have contributed greatly to the book with written material, samples and managerial support. Assaf Azaria works at the IBM Haifa Software Lab in Rehovot, (Ubique) Israel. Assaf has been a member of the Sametime team for more than four years, and is one of the architects of the Sametime server and client toolkits. Harry Hornreich has been development manager for the Sametime Toolkits and Clients in the Haifa Software Lab in Rehovot, (Ubique) Israel, since August 1997. In this role he has driven the development of the Java, C++, Sametime Links,COM and Community Server Toolkits. In addition he is responsible for the Sametime Connect clients which are built on top of these Toolkits. Harry has a M.Sc. in Computer Science from the Technion in Haifa and has more than 12 years experience in software development. Amir Perlman is the team leader for Java technologies at the IBM Haifa Software Lab in Rehovot, (Ubique) Israel. For the last three years he has participated in architecting and developing the Java Toolkits, Sametime links, and the Java connect client. We also extend a special thank you to Jeremy Dies, Lotus Sametime brand manager, and Don Bunch, Lotus Sametime product manager, for their help and support. In addition we send thanks to the following people for their contributions to this project: Christopher Baker, IBM Westford Software Lab Tammy Delk, Lotus Software, Lexington Kentucky Dvir Landerer, IBM Haifa Software Lab, Israel Barry O'Nan, Lotus Software, Lexington Kentucky Yaron Reinharts, IBM Haifa Software Lab, Israel Haim Schneider, IBM Haifa Software Lab, Israel

Preface

xv

Yafit Sami, IBM Haifa Software Lab, Israel Christian Steege, Lotus Professional Services, IBM Switzerland William Tworek, ITSO Team Leader, Cambridge, Massachusetts Alison Chandler, ITSO Poughkeepsie, New York

Comments welcome
Your comments are important to us! We want our Redbooks to be as helpful as possible. Send us your comments about this or other Redbooks in one of the following ways: Use the online Contact us review redbook form found at:
ibm.com/redbooks

Send your comments in an Internet note to:


redbook@us.ibm.com

Mail your comments to the address on page ii.

xvi

Working with the Sametime Client Toolkits

Part 1

Part

Introduction to Sametime client toolkits

Copyright IBM Corp. 2002. All rights reserved.

Working with the Sametime Client Toolkits

Chapter 1.

Introduction to Sametime
In this book we explore the use of the Sametime client toolkits. Our primary target audience is developers and architects, but administrators may also find parts of the book useful. Please note that this book covers examples of toolkit use. Given the rich functionality of the Sametime toolkits, we cannot cover all services and APIs in detail in a single redbook. Instead, we have taken selected examples and explored those in detail. See 1.4, The structure of the book on page 12 for an overview of the examples we cover. Note: The Sametime COM and the Sametime Links toolkits described in this book were not released as final products at the time of writing. There may be minor differences between the described features and installation procedures in this book and those for the released toolkits. In this chapter we start by giving a brief overview of what Sametime really is. Sametime provides services in the areas of instant messaging, online meetings and customization/integration. We discuss these areas and then focus a bit more on the toolkit capabilities of Sametime. We conclude the toolkits overview with a table where we summarize the features and considerations for each of the Sametime client toolkits. Finally, we describe what is covered in the rest of this book. Parts of this introduction are adapted from the Lotus White Paper Real-time Collaboration with Lotus Sametime, Part No. CC7MANA.

Copyright IBM Corp. 2002. All rights reserved.

1.1 What is Sametime


Lotus Sametime is the first real-time collaboration product that offers a complete range of integrated, real-time services while meeting enterprise and e-business requirements for scalability, manageability, and security. Sametime services fall into three areas: Community services: These services include awareness, instant messaging, and chat. A buddy list makes Sametime users aware of who is available (and who is online but unavailable) to receive an instant message or participate in a chat with one or more people. The instant messaging traffic is encrypted. Online Meeting services: These services include a shared whiteboard and the ability to share programs and documents online. Sametime also offers a server-based Meeting Center where users can schedule online meetings in advance and store agendas and other meeting materials. Customization and Integration services: Sametime also provides a comprehensive API that enables customers to easily integrate real-time collaborative capabilities into other applications, such as e-commerce sites, help desks, and training/information delivery applications like Sales Force Automation.

1.1.1 Community services


Most real-time communication is unscheduled and has nothing to do with computer technology. For example, you hear the voice of a colleague outside your office door, and you step out to speak to her face-to-face. Online, real-time collaboration is also very convenient and most effective when it occurs spontaneously, just like the hallway encounter. But like a face-to-face encounter, you need to be aware of the opportunity to interact. Sametime recognizes this fact and incorporates the ability to tell the server your availability. A user can tell the server whether they are online, away from their computer, or they can even ask not to be disturbed. The awareness capabilities of Sametime help make spur-of-the-moment, online conversations as natural, convenient, and worthwhile as a hallway chat. And, in situations where text chat may not be enough, Sametimes audio and video support allows a much more personal and productive tool to complement a typical text chat. Sametime makes users aware of opportunities for online interaction via a sophisticated buddy list, used to identify which members of a community are online and whether they are available to interact. Sametime can obtain the identities of users directly from the enterprise directory (such as an LDAP directory or Domino Directory) or from its own integrated directory.

Working with the Sametime Client Toolkits

Sametime can also provide awareness to customers and business partners outside the firewall through integration with America Onlines Instant Messenger (AIM) service. With the Sametime Connect client, users can exchange instant messages with any AIM user. (Administrators determine whether this Sametime capability is enabled.) Sametime even enables users to replace obscure AOL names with more meaningful nicknames. Once users are aware of who is online, they can initiate interaction simply by sending an instant message. A user might start an instant message, an online meeting, a telephone callwhatever suits the task at hand. For example, an instant message is an efficient, low-bandwidth medium for the quick clarification of an idea; but to explain the details of a design specification, a phone call may be a more appropriate medium. Of course, nobody wants to be available for spontaneous communicationread interruptionall the time. For this reason, Sametime gives each user full control over their availability. Levels of participation include Active (online and available), Away (offline or otherwise unavailable) and Do Not Disturb (online but unavailable).

1.1.2 Sametime Online Meeting services


Sametime Online Meeting or Conferencing Services provide the ability to share objects (such as desktop applications, presentations, documents, and drawings) online. Users can schedule an online meeting in advance, or move directly from an instant message to a screen-sharing or whiteboard session such as the one shown in Figure 1-1 on page 6.

Chapter 1. Introduction to Sametime

Figure 1-1 Client for Sametime whiteboarding session

Sametime allows any user to share any program from his or her desktop, such as word processors, spreadsheets, and project management software. Other participants are not required to have the same software in order to participate and see whats being shared. When appropriate, users can also pass control of the application back and forth as necessary; the initiator can reassert control at any time. Sametimes shared whiteboard is the online equivalent of a typical whiteboard in an office or classroom. Users can draw on it, show presentations, and annotate documents on it. Sametime also converts popular file types into pages for convenient display during whiteboard sessions. As noted previously, Sametime fully supports both ad hoc and scheduled meetings. Online meetings can be anything from a quick show me session among two people, to team briefings on a new product, to a full-scale virtual seminar involving hundreds of participants across both the WAN and the Web. Meeting information is posted in a server-based Meeting Center, along with agendas and preparatory materials. Invitees can access these materials anytime before, during, or after the meeting. For maximum convenience and to eliminate barriers to off-site invitees, users can participate in online meetings and whiteboard sessions directly from Web browsers, without downloading and installing special software or plug-ins. Users can also specify the type of meeting

Working with the Sametime Client Toolkits

to help manage bandwidth. For example, a user can have a meeting that is designed to allow several people to collaborate on a specific application. Sametime also allows a user to set up meetings that are designed for one presenter and a large audience of observers, like an organizational or earnings announcement. The meeting moderator decides which services (chat, whiteboarding, audio/video, etc.) will be available to each participant. In this way the user easily customizes the meeting based on their goals and collaboration needs.

1.1.3 Sametime customization and integration services


In addition to secure instant messaging and online meetings, Sametime offers developers a comprehensive set of tools, components, and APIs to integrate real-time collaboration capabilities with other applications. The APIs are exposed via toolkits that enable you to write client applications in Java, C++, COM or HTML and JavaScript. In addition, there is a Java toolkit for server-side applications. In this book we focus on the capabilities offered by the Sametime client toolkits. The next section provides a brief overview of the different Sametime client toolkits.

1.2 The Sametime client toolkits


In this section we present an overview of the following Sametime client toolkits: Sametime Links toolkit Sametime COM toolkit Sametime Java toolkit Sametime C++ toolkit Finally, we compare their features in a table and discuss their target environments.

1.2.1 The Sametime Links toolkit


Sametime Links is a light toolkit that allows Web developers to enable their Web pages and applications with Sametime live names. A simple HTML/JavaScript API (no Java programming required) allows Web developers to turn existing names into Sametime links by simply adding a few lines of HTML, without affecting the layout of the page. While rich in functionality, it is light in sizeusing an embedded applet of only 20K for connectivity and window management.

Chapter 1. Introduction to Sametime

1.2.2 The Sametime COM toolkit


The Sametime COM toolkit is a subset of the C++ toolkit. It provides the basic Sametime community services, delivered as a standard DLL with interfaces that represent the services provided. This toolkit can be used to enable applications with Sametime in any development environment that supports COM and OLE automation, such as Visual Basic/VBA (Microsoft Office) and JavaScript in Microsoft Internet Explorer.

1.2.3 The Sametime Java toolkit


The Lotus Sametime Java toolkit is a collection of building blocks or components that developers use to build applications which leverage the functionality and services provided by Lotus Sametime. These toolkit components can be used in any standard development environment that supports JDK 1.1 or above.

1.2.4 The Sametime C++ toolkit


The Sametime C++ toolkit is also a collection of components that allow developers to enhance Windows applications with Community services, such as awareness and instant messaging. Using the Microsoft Visual C++ Developer Studio, developers can quickly and easily Sametime-enable any Win32 or MFC-based Windows application.

1.3 Which toolkit to use


The Sametime client toolkits expose Sametime client functionality, targeted to different platforms and developers, to facilitate the development of real-time client applications. There are four main factors to consider when determining which Sametime toolkit to use: 1. Your target platform 2. Required Sametime features 3. Load time 4. Required programming skills You should consider these factors in the order they are discussed in the following sections. You can also refer to Table 1-5 on page 11 for additional comparison information.

Working with the Sametime Client Toolkits

1.3.1 Target platform


The target platform is a combination of operating system and Web browser options. For example, for developers to extend or develop native Windows applications, Sametime offers the COM, Java, and C++ toolkits. For Web applications on Windows, there are three options, depending on whether there is a requirement to support browsers other than Microsoft Internet Explorer. And for non-Windows operating systems, such as UNIX, the Java toolkit is offered. Refer to Table 1-1 for a comparison of Sametime toolkits on various target platforms.
Table 1-1 Target platforms for Sametime toolkits
Toolkits Target platforms Windows Browsers (on Windows) Non-Windows X Sametime Links COM X X1 Java X X X2 C++ X

1 Only with Microsoft Internet Explorer. 2 Only Community Services are supported. UI and Meeting components were only tested on Windows.

1.3.2 Required features


Once you have found the available toolkits for your target platform, you can narrow your choices based on the Sametime features required. All of the client toolkits provide basic community services (awareness and instant messaging). If you require more advanced community services, such as chat meetings (n-way chat) or virtual places, you should consider Sametime Links (for Web applications) and the Java and C++ toolkits for other applications. An additional consideration is that meetings can be launched in a browser from the Sametime Links, Java, and C++ toolkits. Should you need to embed meeting components in your application, you will need to use the Java toolkit. Refer to Table 1-2 on page 10 for a comparison of Sametime features offered by the various Sametime toolkits.

Chapter 1. Introduction to Sametime

Table 1-2 Sametime features in different Sametime toolkits


Toolkits Sametime features Basic Community Services Full Community Services Community UI Launch Meeting Room Embed Meeting Services 1 Partial customization required. 2 Partial support. Sametime Links X X1 X X
2

COM X

Java X X X X
X

C++ X X

1.3.3 Initialization load time


An additional factor to consider is how important the initialization load time is, or how long it takes for the application to start once it is launched by the user. Applications developed on top of the C++ and COM toolkits load relatively quickly, but must be installed. Java applets and applications developed on top of the Java toolkit load relatively slowly, but initialize faster if installed (Java applets must be signed to be installed). Sametime Links also uses a Java applet, but since most of the functionality is provided by the server application, the applet is quite small, and therefore loads quickly without being installed. Refer to Table 1-3 for a comparison of load time offered by the various Sametime toolkits. Since installed applications and applets usually load faster, that information is noted as well.
Table 1-3 Load time comparison
Relatively fast load time Installable on client machine Not installable on client machine C++, COM Sametime Links Relatively slow load time Java (signed) Java

1.3.4 Programming skills


Finally, in order to develop or enhance any application, you need to ensure that you have the appropriate programming skills available.

10

Working with the Sametime Client Toolkits

The following table notes the programming skills required for each of the Sametime client toolkits.
Table 1-4 Programming skills required for different Sametime toolkits
Toolkit Sametime Links COM C++ Java Required skills HTML/JavaScript Windows Visual (COM) C++ Java

This concludes our description of the four main factors to consider when deciding which toolkit to use for development of Sametime client applications. We have discussed them in the order you should consider them, if possible. However, your special situation will decide the right order.

1.3.5 Toolkit comparison


In this section we have summarized the information about the Sametime client toolkits in a single table to help you compare them.
Table 1-5 Comparison of Sametime client toolkits
Sametime Links Major features COM Java Provides all core Sametime community and meeting services and UI components Object-oriented Modular Thread-safe C++ Provides all Community services (but not Meeting services) Object-oriented Modular Thread-safe

Easy to use Basic awareness Light weight (~20K and instant applet) messaging No install Easy to use Does not affect page Works in any layout environment that Customizable supports COM HTML-dialogs ADA1 -compliant

Example uses

Web-based buddy BuddyList e-commerce list app application in Help desk e-commerce Visual Basic Add awareness and application with messaging to Web Add awareness and meetings messaging to MS pages and Office applications Browsers on Windows2 Any Windows application that supports COM Java applets and applications

Adding awareness and messaging to C++ applications

Target environment

Win32- or MFC3 -based Windows applications

Chapter 1. Introduction to Sametime

11

Sametime Links Limitations and considerations Does not expose all functionality Less control Currently only supported on Windows Any Web development environment HTML and basic JavaScript

COM

Java

C++

Comparatively large No UI Only on Windows Only basic features, Appshare host and No meeting services A/V only on no toolkit user or A/V4 Windows interface UI is not components ADA1- compliant Any development environment that supports COM5 Visual or scripting language Any Java development environment that supports JDK 1.1 Java programming skills Microsoft Visual C++ 6.0 Developer Studio SP5 C++ programming skills

Development environment

Required skills Server compatibility

Sametime 1.5 and Sametime 2.6 and 2.x above A standalone add-on installation will be provided for Sametime 2.5 as well
1 2

Sametime 2.x Sametime 2.x Sametime 1.5 Sametime 1.5 can community service also be used, but can also be used for community (though not places services only (not or storage) places or storage)

Americans with Disabilities Act Win95/98/NT/2000/XP, with MSIE 5 and above, and Netscape 4.7 and above 3 Microsoft Foundation Classes 4 Though the Meeting Room can be launched from a C++ application 5 For example, Visual Basic/VBA (Microsoft Office), LotusScript in Lotus Notes, and JavaScript in Microsoft Internet Explorer

1.4 The structure of the book


This redbook is divided into four parts: Introduction to Sametime client toolkits The current chapter is first in the introduction part. In Chapter 2, Sametime toolkit services on page 17 we take a closer look at the Sametime toolkit services from the client toolkit programmers point of view. We describe how most of what happens in Sametime is driven by events, and look at the associated concepts of interfaces, listeners, and adapters. Finally, we describe the core types used in Sametime development. You may or may not access the core types directly in your programming, but it is important to understand what they are and how they are used under all circumstances.

12

Working with the Sametime Client Toolkits

In Chapter 3, Places architecture on page 49 we focus on one particular toolkit service, PlacesService, and describe the Sametime Places architecture with emphasis on what you can do from a client point of view. We also show you the event flows for some common operations in a Sametime place. Java toolkit Chapter 4, Installation and setup on page 71 describes how to get the Sametime Java toolkit and how to set it up to develop and run programs with either the IBM Java Development Kit (JDK) 1.3 or IBM VisualAge for Java 3.5. Chapter 5, Introduction to Sametime Java applets on page 89 contains a skeleton Sametime applet where we describe which Sametime code should be placed in the applet events: init, start, stop, and destroy. We included this chapter to give you a better background for understanding the sample in the next chapter which is based on two applet clients. Chapter 6, A place-based auction example on page 101 is our first large example. It describes how we solve the challenge of having an on-line real-time auction. The sample utilizes the Sametime PlacesService. We show how place members can communicate both by direct messages and by changing attributes, and much more. In Chapter 7, Customized chat UI applet on page 137 we look mostly at a new user interface component introduced in the Sametime 2.5 Java toolkit that allows the developer to customize the look and feel of the ChatUI component. In the first iteration we show how you can add buttons with canned chat messages, add your own logo to the window, and so on. We discuss the different ways you can deploy Sametime applets and walk you through the steps required to deploy via a Domino database. Then we take the sample further by using the Sametime storage service to save our canned messages between invocations, and finally we show how we can launch a new Sametime applet in our browser without requiring the user to authenticate again. This is accomplished by utilizing the Sametime TokenService. C++ toolkit The part covering the C++ toolkit starts with Chapter 8, Working with the C++ toolkit on page 199, where we describe how the get the Sametime C++ toolkit and how to set it up. In Chapter 9, A complex meetings sample on page 207 we have a large example where we basically end up with a client that matches the Sametime Connect client. We start out with a sample from the Sametime C++ toolkit and then add functionality to it. We describe the new classes introduced and discuss four steps to create a meeting, from the initial creation of an invitation to the launching of the Sametime Java Meeting client. Even if you are not a

Chapter 1. Introduction to Sametime

13

C++ programmer, you can learn some interesting things about how to work with Sametime places in this chapter; and if you are a C++ programmer, it should also interest you to see how to launch the Java-based meeting client from a C++ program. Finally, in Chapter 10, Using the C++ toolkit in Win32 programs on page 297 we describe what is different if you want to develop a Win32 program with the Sametime toolkit (in contrast to using the Microsoft Foundation Classes (MFC) which we used in the prior chapter. COM and Links toolkits The last part covers the newest Sametime client toolkits. In Chapter 11, The COM toolkit on page 309 we show how you can build a Sametime BuddyList using Visual Basic. First we describe how to get the COM toolkit and to enable it in Visual Basic. This process is split into three parts, starting with the basic capabilities of logging in and out from the Sametime server, adding awareness of other users, and finally adding the capability to chat with those users. In this sample you can see how you can use the different capabilities of the Sametime COM toolkit to add real-time collaboration abilities to programs like Microsoft Office and your own Visual Basic programs. Finally, Chapter 12, The Sametime Links toolkit on page 355 is about the newest Sametime client toolkit. The Sametime Links toolkit allows a Web page developer to add real-time collaboration capabilities to any Web page without any particular Sametime knowledge. The toolkit only requires HTML and JavaScript skills. A beta version of the Sametime Links toolkit has been available for some time, but the new version has been totally changed. At the time of writing the toolkit was still in development, so we have couched our descriptions of many of the toolkit functions in general terms; the final toolkit may have small differences compared to our description. In addition to these four parts we have some appendices in the book. We start with a few deployment consideration we had during the work on this book. Then we describe how you can set up the sample files we described in Chapter 6. In another appendix we take you through a scenario with screen captures using the same sample, and finally we have an appendix where we show an example of how Sametime can be used in portal solutions. The appendix contains description of two Sametime portlets that run under WebSphere Portal Server.

14

Working with the Sametime Client Toolkits

1.4.1 The Sametime Community Server Toolkit Redbook


This redbook describes some of the things you can do with the various Sametime client toolkits. It was written in conjunction with another IBM Redbook, Working with the Sametime Community Server Toolkit, SG24-6667. That redbook focuses on a new toolkit that allows you to write Sametime server applications. While the client toolkits allow you to utilize the existing Sametime services, the server toolkit allows you to alter and extend those services and to create services of your own. When there is additional coverage of a topic we discuss in this book in Working with the Sametime Community Server Toolkit, SG24-6667 we will refer to it.

1.5 Summary
In this chapter we have given you an overview of the services provided with the Sametime server product. We have briefly described the various Sametime client toolkits and discussed which to use when. Finally, we have described the structure of the rest of the book.

Chapter 1. Introduction to Sametime

15

16

Working with the Sametime Client Toolkits

Chapter 2.

Sametime toolkit services


Depending on your background, developing for Sametime may introduce some new concepts. In this chapter we give a brief overview of how Sametime actually works. We discuss events, listeners, and adapters, as well as how the programming concepts interface, extend, and implement relate to them. We describe the services made available to the developer by the client toolkits. Finally, we dig a little deeper and discuss the core types (like STUser) that are part of the Sametime architecture. Some of these will never be exposed directly to you during use of the Sametime client toolkits. However, knowing what they are and do will help you to get the big picture of what is going on in Sametime as you delve into creating your Sametime solutions.

Copyright IBM Corp. 2002. All rights reserved.

17

2.1 Sametime architecture basics


Sametime is a lightweight, distributed, client/server, event-handling system. What does this mean for you? Lets first define how we understand these terms: Lightweight All toolkits that exist are small. They are just a .DLL file for the COM Toolkit, a .JAR for the Java Toolkit, and so on. The size of the toolkit is very important in the world of Web applications, since the application and the toolkit are often just downloaded from the server when they are used. Users, servers, and other Sametime objects are usually distributed over geographically distant locations. This is hidden for the programmer since he does not need to recognize where the object he works with is located, and it even can move like a user who logs into Sametime from another computer. The Sametime server provides an extensible set of services to the Sametime users. On the clients there is usually client application logic and some components of the toolkit which interact with the application. The toolkit accepts certain activities of the client application and sends them to the server, but also notifies the client application about information coming from the server. This is shown in Figure 2-1 on page 19. Sametime distributes event notifications from Sametime objects to other Sametime objects, including your applications working with these objects. Sametime does not offer a low-level event management system, but adds a layer of concepts for direct reuse. Thus, Sametime introduces users and a user status together with a watchlist. A watchlist contains Sametime objects (users), and will notify your application automatically when the user changes his status.

Distributed

Client/Server

Event-handling

18

Working with the Sametime Client Toolkits

Client Application

Sametime Toolkit

TCP/IP Socket connection or HTTP Requests

Sametime Server

Figure 2-1 Sametime Client/Server applications

There is much more to the Sametime server architecture, but here we focus on what you need to know from a client program point of view. To learn more about the Sametime server architecture see the redbook Working with the Sametime Community Server Toolkit, SG24-6667.

2.1.1 Proxy objects


As is usual for networked or distributed object infrastructures, Sametime uses the proxy concept to make the developers life easier. Most of the objects you will work with are, in most cases, only local proxies to objects in a Sametime server, which again may be in a community of servers and not the server you are connected to. Figure 2-2 on page 20 shows how such a scenario looks. The client application is working with the proxy objects as if they were the real object (for instance, a user or a place). In reality, the proxy object only contains stubs which convert the method calls into network traversing events. On the Sametime server, the request is received and converted into a call to the real object.

Chapter 2. Sametime toolkit services

19

Client Application
User Proxy Object Application Logic Place Proxy Object

Toolkit

Sametime Server

Community Service Session

Community Service

User Object

Places Service

Places Service

Place Object

Figure 2-2 Proxy objects and server side objects

It is important to note that in Sametime the server-side object also can send events to the client applicationthis means that the server-side object can notify all clients who are having a proxy object. As you see, Sametime keeps the developer well away from handling the connection to the original object, but it is still important always to remember what happens in the background.

2.1.2 The Model-View-Controller paradigm


A common concept for the flexible design of applications with a user interface is the Model-View-Controller (MVC) paradigm. The intention is to disconnect the application logic and the user interface, and thereby remove some very common problems programmers run into. In a monolithic application you often find application logic and user interface with a complex connection. It is hard to maintain both parts independently. If an application is designed with MVC in mind, the application is split into three different types of components: Model View Controller The application logic (object) with no user interface One or more UI components rendering the model One or more user interaction components controlling I/O devices like a mouse or keyboard

20

Working with the Sametime Client Toolkits

The component types are interconnected, as shown in Figure 2-3. Here, connected means that the objects know of each other. Typically, this means: The model maintains a list of listeners - objects that are interested to know if the model is changed; for instance, if an attribute is updated. If this happens, the model notifies all listeners of the event. The views store a reference to their model, and interact with its controller. The controller stores a reference to its view.

Controller 1

Controller2

View 1

View 2

Model

Figure 2-3 MVC Design Paradigm

If the model is updated for some reason, all listeners are notified. All views update themselves if the update is relevant. (The update may concern an attribute not shown by the view at all, and so the view does not need to be updated.) The other way of interaction is that the controller catches an event from the operating systems I/O devices, like a mouse click. In this case it evaluates, together with the view, whether the event needs to be handled, and if so, it calls an appropriate method of the model. The Sametime Java toolkit is designed according to the MVC paradigm. It provides non-visual classes, for instance a Place which a Sametime application can enter. It also provides visual elements, for instance a PlaceAwarenessList, which can easily be associated with a place. The PlaceAwarenessList delivers, by default, a ChatController that allows instant messaging with the users in the

Chapter 2. Sametime toolkit services

21

list. You can always exchange this controller with another controller, for instance an AVController, which allows you to run instant meetings, including Audio/Video conferences, if the server has the features installed. Figure 2-4 shows the Sametime interpretation of MVC.

Client computer 1 ChatController

Client computer 2 AVController

PlaceAwarenessList 1

PlaceAwareness.List 2

Place

Sametime Server 1

Sametime Server 2

Figure 2-4 Sametime MVC interpretation

It is important to reiterate that the Sametime architecture is distributed: the place watched by the PlaceAwarenessList is on the server, while the views are on the client computers (usually on different ones). If you use the PlaceAwarenessList from the Sametime toolkit and bind it to your Place proxy object, it will automatically watch the place, that is, it will show the users in the place and allow you to initiate conversations with them.

2.1.3 Sametime events


Sametime uses an event model to logically disconnect the client-side components from the server-side components. Many actions your application takes on the local objects initiate communication to the Sametime server. Instead of waiting for the communication to finish, your application can continue to do other tasks.

22

Working with the Sametime Client Toolkits

Also, events from the server may arrive in a different sequence than the actions sent to the server occurred. This is an important feature, since some actions on the server may take longer than others. The events are categorized into interface definitions associated with the services they are related to, called Listeners. You will see in the remainder of this book that there are several services to use and they all bring interfaces to be implemented. For a simple implementation example of how this works, see 5.1.6, Using the LoginListener interface on page 94. However, the use of interfaces and listeners may seem more complex in other examples, so in the next section we explore the concepts of events, interfaces, listeners, and adapters in more depth.

2.2 Interfaces and other funny words


If your background is programming in languages such as Visual Basic or LotusScript, you may not have used things like interfaces, listeners, and event adapters before. In this section we discuss the following concepts: Event Interface Listener Adapter We also discuss the differences between what it means to extend and to implement in Java.

2.2.1 Event
An event is something that happens during the execution of an application and that may alter the course of what happens next: a key is pressed, the mouse is clicked, a Sametime user sends you a message, and so on. Events do not necessarily come directly from the user and new events can be defined by the programmer. The Sametime toolkits provides a lot of events that you can (or rather must) use in your programming. When you request a service from Sametime, or issue a command against Sametime, in most cases you do not get an immediate reply (a return code, a handle, or similar) as you do with a remote procedure call. The reply is delivered by an event. You will only get this event if you have subscribed

Chapter 2. Sametime toolkit services

23

to the group of events that the required event is part of. Thus to know whether the things you do succeed or fail you must subscribe to events. To get handles to other Sametime objects (like sections in a place you just entered) you must subscribe to events, and so on. For example, to know whether your login attempt to the Sametime server was successful you must subscribe to the login events, which either can be loggedIn or loggedOut (which you also get if a login request was refused). Another example is if you enter a Sametime place. To know you have entered successfully and to get a handle to your own section in the place, to get a handle to yourself in the place, and so on, you need to receive the entered event. However, to get this event you must subscribe to the full group of Place events (which number 17 in all) and you have to handle them all. This may just mean that you a have a method that does nothing for each of those event messages that you have no interest in, but you still need to have those methods or your program will break. The question is then: How do you know which event messages you need to implement methods for? You can, of course, look in the documentation, but there is a better way to make sure that your class implements all required methods. That is by using an event interface. We describe what an interface is in the next section.

2.2.2 Interface
When you work with the Sametime Java and C++ toolkits, you will be working with interfaces. Some books talk on a high and abstract level about interfaces as a way to implement something that is better than multiple inheritance in object-oriented (OO) programming. However, we will keep our discussion of interface on a pragmatic level and try to illustrate how interfaces are used in a Sametime context. First, lets look at the general definition of interface. Definition: An interface is a named collection of method definitions (without implementations). An interface can also declare constants. An interface gives a list of prototypes for methods that must be provided by any class that implements the interface. An interface does not implement methods, it only defines them. A class that implements the interface agrees to implement all the methods defined in the interface, thereby agreeing to certain behavior. (This is what some teachers of OO programming call making a contract.)

24

Working with the Sametime Client Toolkits

Lets go back to the example we discussed in 2.2.1, Event on page 23 where we needed to make sure that we had methods for all the possible event messages we might receive when we subscribe to Place events. We handle this by implementing in our class a PlaceListener interface provided by the Sametime toolkit. When we decide to implement an interface in our class, the compiler makes sure that we really also have created methods for all the method definitions provided by the interface. A class can implement as many interfaces as the programmer wants. For example, a single class can listen to both Place, Section, and UserInPlace events. All that is needed is that the class implements three different Sametime Listener interfaces. You can also think of an interface as a language. If a class implements three interfaces, any object that wants to talk to it must at least talk one of the three languages. By implementing the PlaceListener interface, our class can handle any event that may come when it subscribes to listen to a place. Our class thus gets the capabilities of a PlaceListener; in other words, it becomes a PlaceListener. A class that implements a certain Sametime Listener interface becomes a Listener of that certain type. This leads us to the topic of the next section, Listeners.

2.2.3 Listener
A listener is an object that listens for particular sorts of events. Listeners must be instantiated from classes that implement listener interfaces. Sometimes, depending on the complexity (amount of event messages) of the interface, the listening responsibility is added to a class that has other responsibilities as well. Sometimes a class is dedicated solely to the handling of the messages defined by the listener interface. Such a class typically extends an Adapter class, which we will discuss in the next section. Lets discuss listeners in a Sametime context first. If a class in your application is to be a Sametime event listener, it must do the following: Implement a Listener interface for the group of Sametime events it wants to listen to. For example, the class responsible for logging into the Sametime community must implement the LoginListerner interface. To do this the class must contains definitions for the methods loggedIn and LoggedOut. Subscribe to be notified about the group of Sametime events.

Chapter 2. Sametime toolkit services

25

For example, to be notified about Login events, the class instantiation (or another object) must send the addLoginListener message to the community service object in Sametime and pass the object that must receive the events (our class instantiation) as a parameter. (To stop listening to Login events you must use the message removeLoginListener and pass the same object as a parameter.) As we discussed previously, a class can implement many interfaces and thus also listen to several groups of Sametime events. While it may make sense to keep the logic that handles various Sametime events in one class, the class may become very large because of the requirement that it implements all methods defined in all the Listener interfaces it has to subscribe to. In such cases, listening to the different groups of events can be delegated to objects called Adapters, which we discuss in the next section.

2.2.4 Adapter
A class that implements an interface must provide code for all the methods in the interface. This can be a lot of dull work in cases where you only are interested in a few of the event messages. Adapters provide dummy bodies that do nothing for all the methods in a particular interface. If a listener inherits from an adapter, it need only provide code for the appropriate methods, leaving the default bodies for the others. The Sametime Java and C++ toolkits provide Adapter classes to match all the Listener interfaces defined. To illustrate the advantage of Adapters, lets ponder an example where you have entered a Sametime place in your application. Your application includes a user interface class which has the responsibility of displaying the value of some of the place attributes. To be notified about the value of place attributes and when they change you need to implement the PlaceListener interface and subscribe to Place events. If you want your user interface class to listen directly for the attribute values (sent by the attributeChanged message), the class also has to handle the 16 other messages that may be generated by the place. To avoid cluttering your user interface class with 16 do-nothing methods, you can create another class to handle the listener responsibility. If you create this class as a subclass of the PlaceAdapter supplied by the Sametime toolkit, all you need in your subclass is a constructor, the attributeChanged method and a variable to keep a reference to the user interface object. You do not need to define methods for the other 16 event messages because they are defined in the PlaceAdapter superclass.

26

Working with the Sametime Client Toolkits

You can then use the addPlaceListener method against the place and pass your new adapter class as the parameter. When the adapter class receives the attributeChanged method, it can either pass it directly on to the user interface object that it has a reference to or it can do some processing on the received event before passing it on. Using an adapter in this example, you get the following advantages: The class with your application logic or user interface logic does not have to be cluttered with a lot of do-nothing methods to handle events you not are interested in. You do not have to implement the Listener interface in your adapter class since this is handled by the superclass. The adapter subclass only has to define methods for events it wants to process. All other events are passed on to the adapter superclass for default processing. The developer can immediately see which events in a group are handled by the listener and which are ignored. You can choose between simply having your adapter class pass the interesting messages on or you can do some processing in your listener. For example, you can handle the attributeChanged message in your listener, determine which attribute is changed, and only pass the event on if it is a subset of attributes that you are interested in. In such a case you can also let the adapter invoke different methods for different attributes in your receiving object. On the flip side you get more classes in your application when using listener classes that inherit from adapters. It may be harder for the maintenance developer to understand the relationships between the classes. In Java, one way to make it easier to see which class a listener class serves is to use inner classes.

Using nested classes in Java as listeners


We start this discussion with a brief introduction to nested classes. Java lets you define a class as a member of another class. This is called a nested class. You use a nested class only when it makes sense in the context of its containing class. A nested class has unlimited access to all (including private) members of its containing class. There are two types of nested classes. If the enclosed class is static, it is called a static nested class. If it is dynamic, the class is called an inner class. An inner class has direct access to instance variables and methods of its containing class.

Chapter 2. Sametime toolkit services

27

If you define your listener classes that inherit from adapters as inner classes of the class they server, you get both the advantage that it is easy to see that the classes relate to each other, as well as the fact that the inner class gets direct access to the variables and methods of the containing class. To see an example of this in action you can study the Sametime 2.5 Java toolkit sample named ChatMeeting. The main class is also named ChatMeeting and it has the following three inner classes: CommunityEventsListener This class implements the LoginListener interface and handles the login events for the ChatMeeting class. When it receives the loggedIn message, it in turn invokes the enterPlace() method in the containing class. This class does not extend an adapter because the interface only defines two messages which both need to be handled. ParticipantListListener This class extends the AwarenessViewAdapter class. It keeps track of the number of users in the chat and updates variables in the containing class when the number changes. PlaceEventsListener This class extends the PlaceAdapter class. It only handles the entered message out of the 17 possible Place events, and it does so by invoking methods on objects referred to by variables in the containing class. By using separate classes that extend the AwarenessViewAdapter and the PlaceAdapter, we have been saved from having to implement 21 do-nothing methods required by the corresponding interfaces. In addition, by making the classes inner classes of the class that uses them, it is easier to see the relationship between the classes. This concludes our discussion of interfaces and other concepts related to the handling of Sametime events. Before moving on we also want to look at the meaning of extend and implement when used in Java.

2.2.5 Extend and implement


If looking at sample programs supplied with the Sametime Java Toolkit is your first exposure to Java, or close to it, you may wonder what the extend and implement keywords in the class definitions mean.

Extend
Extend is Java-speak for subclass. In Java the class that is extended is the superclass for your class. Java has single inheritance and thus there is only one class that your class extends.

28

Working with the Sametime Client Toolkits

Implement
The implement keyword in Java is followed by one or more Interfaces. You can only implement interfaces in your class. For each interface you state that your class is implementing the Java compiler check whether you really have implemented all methods defined by the interface.

Extend or implement an interface


The confusion can be endless if you want: An interface can both be extended and implemented. As a user of the Sametime toolkit you will only implement the provided interfaces. On the other hand, if you create a programming framework of your own you may create an interface, and then create another interface that extends your first interface. Just like a class can inherit from a superclass by extending it, an interface can inherit method definitions from another interface by extending it and then provide additional method definitions. However, coming back to the situation where you simply are a user of the Sametime toolkit, you may see sample programs (or write some of your own) where the listener object extends another listener object. The important thing to keep in mind here is that is it not an interface that is being extended in this case, but rather an Adapter class that in turn implements a Listener interface as we discussed in 2.2.4, Adapter on page 26. This concludes our discussion of Interface and other funny words. We will now move on to look at the services provided by the Sametime toolkits.

2.3 Sametime services: What can I do with them


In this section we describe the community and meeting services provided by the Sametime client toolkits. In this redbook we focus on the community services, but we do provide a brief overview of the meeting services as well. By providing isolated services (though some of them depend on each other as you can see on the documentation provided by the toolkit), the Sametime API stays extendable. Two main benefits are realized by this: Future Sametime versions can add services and still work with older applications and toolkits. You can exchange the toolkit with a newer version without changing your application as long as the existing services have not changed the API. Figure 2-5 on page 30 shows an overview of the different Sametime services.

Chapter 2. Sametime toolkit services

29

STSession

STCompAPI

StreamedMediaBroadCastFactory

Community Places Lookup Storage Directory

Awareness Instant Messaging Token Names Post

Meeting Component Streamed Media AppShare WhiteBoard

Meeting Services
Core Types

Community Services
Figure 2-5 Sametime toolkit services

Note that all services are not supported by all Sametime client toolkits. Refer to 1.2, The Sametime client toolkits on page 7 for information about which services the different toolkits support. The Java toolkit also provides Community User Interface components (not shown on the figure).

2.3.1 General features


Most services feature some common functionality, which we want to describe first. Services are defined as interfaces, and implemented by a class. For instance, the places service is defined as the PlacesService interface, and this interface is implemented by the PlacesComp class. Using the isServiceAvailable() method, your application can sense if a service is available. Most applications dont do this yet, and today Sametime offers no documented way to install a server with a subset of services, but you can already just stop a service on the fly. So, use this feature to ensure that your application works in any environment. We show an example of this in 9.2.1, The MeetingUI class on page 213.

30

Working with the Sametime Client Toolkits

Your application can listen to the service and so receive events when the service becomes unavailable or is available again. You will use this if you decided to sense for service availability as described in the preceding paragraph. The other methods of a service interface are performing special tasks, which we describe in the following sections.

2.3.2 Community service


Note: The community service, together with other services like Awareness, Places, and so on, is called Community services as a group. This can be a bit confusing, but Community services refers to a group of services in the same way Meeting services do. The community service that we describe in this section is simply of one of the Community service s. The community service is the fundamental service you use to authenticate to the Sametime infrastructure. Additionally, you can use the community service to change your online status and your privacy settings (Who can see if I am online). Authentication is done using LoginByPassword() if your user supplies a password, or LoginByToken() when you have integrated your application into a single signon environment that provides a one-time passwordthe token. A very interesting feature is the anonymous authentication you can use with LoginAsAnonymous(). This means a user can enter the Sametime community without having a record in the Sametime directory. An example where this is very useful is if you want to be aware of users visiting your Web site. You can launch a hidden applet together with your Web page that logs the visitor in anonymously to your Sametime server. You will then be able to monitor the actions of the user. You will also be able to initiate an instant messaging session with the user, or let different anonymous users have instant messaging sessions with each other, and so on. In Chapter 6, A place-based auction example on page 101 you can see an example of an application that utilizes the ability to log in anonymously. Another component of the community service is the AdminMsgListener interface. Sametime administrators can send messages to all Sametime users logged in. If your application subscribes to this interface, it can catch the message and display it in another way. See Figure 2-6 on page 32 for an administrators message box.

Chapter 2. Sametime toolkit services

31

Figure 2-6 Message from administrator

2.3.3 Awareness service


The awareness service provides the ability to watch Sametime objects, like users, groups, and servers. For users, this means the user status or any attribute associated with it. Groups are referred as server-side groups (of the directory), and their content does not need to be visible to the client application: only the attributes and status of online users is received. Server attributes are, for instance, used by the connect client to show the availability of meeting services.

Figure 2-7 User attributes

Sametime itself uses the attributes, as you can see in Figure 2-7. The Tools dialog is used to set your attributes so that other users can see, for example, if you have a video camera or not. Another use of attributes is shown in Figure 2-8 on page 33, where the buttons in the connect client reflect the availability of meeting and multimedia services at the server. Sametime connect shows only the features installed.

32

Working with the Sametime Client Toolkits

Figure 2-8 Server attributes

Note that attributes are automatically filtered on the server for performance reasons, so your application has to modify the filter to receive the relevant attribute updates using AttrFilter. To watch a list of users you just create a watch list using createWatchList(), add the objects to watch using addItem() and you are done. But dont forget to add a StatusListener so that you receive the updates from the server. You also can change your own attributes using changeMyAttr().

2.3.4 Places service


The key function of a place is that it maintains the list of place members on the server, so your applications dont have to worry about this. If your client applications have all entered the place, you can send messages to the place object and they will be forwarded to all place members, including yourself. So you could think of a notification system where users enter places of interest, and messages for these users are just sent to the place. A very simple example is a chat room. But the Places service does more. It is a complete framework for real-time collaborative applications, in any environmentB2E, B2B, or B2C. A more detailed description of the places architecture can be found in Chapter 3, Places architecture on page 49. This redbook also includes detailed examples that utilize the places architecture: see Chapter 6, A place-based auction example on page 101 and Chapter 9, A complex meetings sample on page 207, which also includes the use of meeting services.

2.3.5 Lookup service


The Lookup service allows you to resolve user and group names to their unique IDs using a resolver object, and to query the group content of server-side groups in the directory. Be aware that such server-side groups may be very large.

Chapter 2. Sametime toolkit services

33

2.3.6 Instant messaging service


The Instant messaging (IM) service allows you to create channels from one client to another via the server, and to transmit text or binary data messages easily. This is the service used when two Sametime users chat, so it is currently, by far, the most used service.

2.3.7 Token service


Token service is used to generate a token for your current login to enable other components of the application or other Sametime applications on the same machine to log into Sametime again without requiring them to know the user password. The token service is used for meeting services components logging in with separate connections, as shown in Chapter 9, A complex meetings sample on page 207. We also show an example of how a Java applet in a browser can login to Sametime using a token supplied by another applet in 7.9, Passing a token between applets on page 183.
If you want to provide single signon integration in a combined Domino/Sametime environment, you have to use the token creation agents described in Appendix A of the Sametime 2.5 Java Toolkit Developers Guide. We show an example of this in 7.6.1, Integrating with a Domino application on page 164. Note the following important items when you work with the token service: For login, use the User ID, not any login name, since Sametime will not perform a resolve as it does for other logins using a password. Use the token quickly since it may expire after some minutes if the Sametime server administrator has enabled an agent called SametimeSecretGenerator. Otherwise (as of Sametime 2.5) a token is valid the day it is generated and the following day.

2.3.8 Storage service


The Storage service is designed to save and load information fragments on the Sametime server. The information is always associated with the currently logged in user. Since the information is stored (only) on the server, your Sametime application can, for instance, be completely workstation-independent and still easily store and access preferences for the users convenience. The information is stored on your home Sametime server, and is retrieved from this server, even when you logged into another server.

34

Working with the Sametime Client Toolkits

Sametime uses the storage service to store your buddy list on the server and allows users to do roaming. A very good example of the use of the storage service is the Buddy List sample application in the Sametime 3.0 Java Toolkit. We also show an example of using the storage service in 7.7, Extending the functionality on page 173. You should avoid making your application completely dependent on the storage service; the application should have acceptable defaults to work independently in case the storage service is not available. You also should not store large amounts of data using this service because it is not designed and optimized for this.

2.3.9 Names service


The Names service is a local service Sametime offers to change the displayed names of users inside your application to their so-called nicknames. You can use this, for instance, to make the displayed names shorter automatically, so that they do not need so much space, or to remove parts of the names (like the first name or the hierarchy display if this is not useful for the users). You also can use it to enable the user to change the display of names in the application manually so that they become easier to remember. Imagine a large scale deployment with a lot of John Smiths, ending up in John Smith1 to John Smith 23. Now the user can change the display name John Smith5 to John Smith, or Jack Smith, or whatever is easiest to remember and has meaning for the user. Sametime Connect uses this service to provide Automatic Nicknames for users. This is a way to quickly shorten all the names of the users in the buddy list by having the name cut at some predefined delimiter, which is often the / delimiter in a hierarchical name. For example, Thor Jensen/TecKraft/US will instead be shown as Thor Jensen.

2.3.10 Directory service


The directory describing the Sametime community members is a very important component of any Sametime infrastructure. Applications may need the user to look up names in a directory by browsing it, showing a segment of the directory and allowing the user to select names from it.

Chapter 2. Sametime toolkit services

35

To do this, you can use the directory service. First ask the directory service for the list of directories using queryAllDirectories(), and then work with the received directory object. With setMaxEntries() you define the number of entries you want to read (remember, directories are usually very large). The Sametime Java toolkit offers a default UI for directory browsing, so you often do not have to implement this at all. Figure 2-9 shows how the UI looks. The Java Toolkit contains the Directory Panel sample, giving you insight on how to use this service.

Figure 2-9 Sametime directory UI

Sametime 3.0 supports two types of directories directly: Domino and LDAP. A Domino directory can be accessed via LDAP also. Depending on the directory configuration, directory browsing might not be available on your Sametime server. For example, directory browsing is not available when using an LDAP directory. When directory browsing is not available, the developer should limit the application to the use of the Lookup service (see 2.3.5, Lookup service on page 33) that provides name-resolving capabilities.

2.3.11 Post service


The post service is a local Sametime service that allows you easily to send an instant message to a list of users, with the option that they may respond.

36

Working with the Sametime Client Toolkits

A typical use is to notify a list of users (you already have) of an event. It can be used, for instance, to remind the attendees of a meeting to attend now, or even to invite them to a meeting, as shown in Chapter 9, A complex meetings sample on page 207. Remember that IMs are created locally, so your network connection will be used to carry out the channel creations. You may want to consider using a place, but this means that you have to make the users enter the place before you use the post service.

2.3.12 Meeting services


Meeting services allow client Java applets and applications to create and join multi-participant meetings. These services are used to share and annotate documents, share and control applications, and communicate using live audio and video. Developers choose the tools to use in a meeting, and can control the visual layout and containments of various UI components.
The Meeting services include application sharing, shared whiteboard, and IP audio and video, and also provide a highly scalable and lightweight Broadcast Receiver. The Broadcast Receiver receives and interprets audio, video, and data streams generated by the different Meeting services, and renders these without actively participating in the meeting. Meeting services provide real-time collaboration services for meetings. Most Meeting services rely on Community services and provide Java Abstract Window Toolkit (AWT) components to display the different activities they represent. AWT is a large collection of classes for building graphical user interfaces in Java. Table 2-1 on page 38 lists and describes the Meeting services available in the Sametime 3.0 Java Toolkit. Note: Meeting services are available only in the Java Toolkit. But still it is possible for a C++ Application to make use of the meeting services. We show this in Chapter 9, A complex meetings sample on page 207.

Chapter 2. Sametime toolkit services

37

Table 2-1 Meeting services


Name of service Application sharing service Description This service provides the ability to select a running application and share it with other online users. It provides an AWT component that displays the shared application and allows remote users to control it. The Application sharing service allows applications to be shared within the context of a place. Additionally, clients within a place are able to view and/or control the shared application. Common uses include on-line editing, remote control, software demonstrations, and presentations. This service provides the ability to mark up a shared whiteboard. It provides an AWT component that displays the whiteboard and handles the different input tools. The Whiteboard service allows users within a place to simultaneously view and annotate attached content and to create whiteboard content by using a basic set of tools (lines, boxes, circles, text, etc.) for drawing. Whiteboard content, such as a PowerPoint or Freelance presentation, can be attached to a meeting created in the Sametime Meeting Center. Developers can either programmatically control the various whiteboard elements (such as switching between documents and pages and selecting drawing tools/colors/stroke widths) or use a default set of AWT components that encompass complete whiteboard functionality. The Meeting factory services handle the authenticated connection to the Sametime server used by the various meeting components (application sharing, whiteboard, audio/video). Objects can register themselves and receive information about the connection and meeting join process.

Whiteboard service

Meeting factory services

2.3.13 Streamed media


One of the major features of Sametime 2.0 was the addition of IP audio and video. When you use the Java Toolkit, you can access these capabilities in your own applications. Once you have a place object with audio or video activities defined, you can manipulate different features of these activities, such as muting a microphone or pausing the video camera. In addition, you can create an AWT panel to display local or incoming video. This same technique can be used for scheduled, instant, and broadcast meetings. Table 2-2 on page 39 gives an overview of the streamed media services in Sametime.

38

Working with the Sametime Client Toolkits

Table 2-2 Streamed media services


Name of service General streamed media service Description The Streamed media service allows clients to access audio, video, and/or data content in a meeting. This service handles all service-level aspects of controlling the content streams, including support for audio mute and pause/play of video. The specific implementation of the service determines which types of content are available and whether the content can be both transmitted and received, or received only. This service provides the ability to receive and transmit IP audio and video. It allows control of the audio and video activities (for example, mute microphone, pause video) and provides an AWT component that displays both local and incoming video. The streamed media interactive service provides clients with two-way communication via audio and video within the context of a place. This service encompasses all the functionality needed to participate in a two-way or multiple-way IP audio/video call. The service handles all semantic-level aspects of controlling the audio and video streams, including support for audio mute, pause/play of video, display of the video stream, and conducted or request-mode audio calls. This service provides receive-only IP audio, video, and data services, which allows for large meetings with many passive participants. This Toolkit service is the only one that does not require login to the community or use of any Community Services to work properly

Streamed media interactive service

Streamed media broadcast service

This concludes our walkthrough of the Sametime services. The services offered obviously map to the architecture of the Sametime server. However, since we concentrate on the Sametime client toolkits in this book, we will not look into the internal architecture of the Sametime server.

2.4 The bare necessities for a client program


As you can see, Sametime offers a wide variety of services, and there is no single pattern for how a Sametime client application should be structured. There are many right ways to program for Sametime. However, to get access to the Sametime services you have to log into the Sametime community. Thus, all Sametime applications must log into a Sametime server during their initialization. In the Java and C++ toolkit samples provided with Sametime 3.0, there is a Login program that illustrates the bare necessities for getting access to Sametime services. We encourage you to find either the Java or the C++ Login sample and

Chapter 2. Sametime toolkit services

39

take a look at the source code. We will walk you through a Login to a Sametime community and illustrate it with code snippets from the Java sample Login program. If you want to see all the Java source code in context, refer to Chapter 5, Introduction to Sametime Java applets on page 89, where we walk through the structure of a basic Sametime-enabled applet.

2.4.1 Create a Sametime session and load components


The first thing you do in your Sametime program is to create a Sametime session:
m_session = new STSession("LoginApplet " + this);

Each Sametime session must have a name. Create a string by appending an object identifier to the string LoginApplet. However, if the session name given turns out to be in use already an exception will be thrown. If creating the Sametime session goes well, you must load the components (or services) that you want to use in your application into the Sametime session. Take the easy way out in this basic sample and load all community services components:
m_session.loadAllComponents();

The documentation provided with the Sametime Java and C++ toolkits discusses how to load individual components. Once the necessary components have been loaded you can start the Sametime session:
m_session.start();

Later on, when our application is stopped, we also need to stop the Sametime session and unload it. We are now ready to log in.

2.4.2 Login to the Sametime community


When you log into the Sametime community you/your application becomes visible to other users in the community.

Getting a reference to STBase - the community service


The STBase component implements the Community service interface and is responsible for logging in and out of the Sametime community. Since the STBase component is loaded when all components are loaded to the session, you must get a reference to this component to be able to log in (The C++ sample only loads the CommunityService and does, thus, have a reference right away). The following code gets the necessary reference:

40

Working with the Sametime Client Toolkits

m_comm = (CommunityService)m_session.getCompApi(CommunityService.COMP_NAME);

The STSession.getCompApi() method requests a reference to a component, based on its name. Every Sametime component has a COMP_NAME field used for this purpose. The name of the STBase component is CommunityService.COMP_NAME. The returned component reference needs to be cast to the right type, since STSession does not distinguish between components and does not know the type of the requested component.

Adding a LoginListener
Because you are connecting to a remote community, the login process can take time. It involves initiating the connection to the server, sending authentication data, and waiting for confirmation. To avoid waiting for the confirmation, you can ask the Community service to notify you when the login procedure is finished. Do this by adding a login listener before attempting to log in:
m_comm.addLoginListener(this);

Logging in
You are now ready to log in. You can try to log in as an authenticated user by passing a user ID and password, or by passing a token. You can also attempt anonymous login. This is an example of logging in by user ID and password:
m_comm.loginByPassword(getCodeBase().getHost().toString(), getParameter("loginName"), getParameter("password"));

Receiving a Login event


Upon a successful login you receive the following event because you added your own object as a LoginListener:
public void loggedIn(LoginEvent event)

If your login attempt was refused, you would receive the loggedOut event, together with an reason code that explains why you could not log in. Besides the community service, your basic Sametime program also needs to import the Sametime core types like STUser. This concludes the bare necessities that (almost) any Sametime program must go through to start utilizing the Sametime services, but we explain more about the Sametime core types in the next section.

Chapter 2. Sametime toolkit services

41

2.5 Core types


The purpose of this section is to explore the core types that are used in the Sametime client toolkits. Every core type represents a Sametime entity that is used and shared by all the Sametime services provided in the toolkit. Depending on which of the Sametime client toolkits you work with, you may never work directly with the Sametime core types. However, if you debug your programs and inspect your Sametime objects, you will encounter core type objects. You will probably benefit most from this section if you already have some Sametime development experience. If you are brand new to Sametime, you can skim the section the first time and then re-read it once you have been through the rest of the book. In this section we discuss: Importing the core types in your classes ID types STId STLoginId Object types STUser STGroup STServer STUserInstance Attribute types STAttribute STExtendedAttribute, including Heavy and Existential

2.5.1 Importing the core types


All Sametime programs must have the core types imported. Here we describe how you do it for Java and C++ programs.

For Java developers


The core types in the Sametime Java toolkit are in the package: com.lotus.sametime.core.types

For C++ developers


The core types in the Sametime C++ toolkit are in the stcommon.lib and the header files in the stcommon folder under inc.

42

Working with the Sametime Client Toolkits

2.5.2 Sametime ID types


The class diagram in Figure 2-10 displays the classes representing the Sametime Identification classes.

STId

STLoginId
Figure 2-10 Sametime IDs class diagram

These classes are mainly for internal use and are not exposed at the API level. The Sametime API uses more high-level entity definitions that encapsulate the Sametime ID within.

STId
STId is a Sametime entity identification. Every Sametime entity has its own unique persistent ID within the Sametime community. The format and content of the ID may vary among different communities and is dependent on the companys directory that is integrated with Sametime (Domino, LDAP).

STLoginId
STLoginId represents a Sametime entitys runtime session identification. While all Sametime entities have their STId, some of them will also have session IDs assigned to them during runtime. For example: A user has its own fixed ID (for example, John Smith/IBM). When the user logs into Sametime, a Login ID will be assigned to him (multiple concurrent logins will result in different login IDs). This information can be used to access a specific login of the user and is valid only for the duration of the login. See the Java or C++ toolkit Tutorials for more information on the Sametime user model.

Chapter 2. Sametime toolkit services

43

2.5.3 Sametime object types


The Sametime entities class diagram is shown in Figure 2-11.

STObjectImpl

STObject

STGroup

STUser

STServer

STUserInstance
Figure 2-11 Sametime entities class diagram

In this section we describe the elements shown in the diagram.

STObject
The STObject interface/abstract class (the former for Java and the latter for C++) provides a general definition for a Sametime entity. Every Sametime entity must implement this interface/abstract class. The definition of a Sametime entity is made up of three parts: Sametime ID Every Sametime entity is uniquely identified by its ID. Name The entitys name. Description Additional descriptive information for the Sametime entity.

STObjectImpl
Currently there are three Sametime entities defined: STUser, STGroup, STServer. Since the implementation is common for all these classes, we added the STObjectImpl, which is used as the base class for the classes implementing the STObject interface/abstract class.

44

Working with the Sametime Client Toolkits

STUser
STUser represents a Sametime user in the community. Since Sametime provides user-to-user interaction, this is the most commonly used structure. In order to interact with other users in the community, the application will need to obtain a valid STUser object. This can be done in one of three ways: Start with a user name and search (resolve) for the matching STUser object using the LookupService. Look through the directory and locate the requested user and its matching STUser object. This functionality is provided through the DirectoryService API. Create the STUser object from scratch. This is an advanced option and requires knowledge of the specific ID allocated for the user. This information may vary among different Sametime installation environments and therefore should only be used by advanced developers who have intimate knowledge of the directory used by Sametime. Once the STUser object is available, the application can perform user-to-user interactions such as: watch a users online status, send instant messages, invite to meetings. Note that some of the services, such as the Awareness service, extend the STUser base class and provide service-specific properties and APIs. For example: STWatchedUser that is provided by Awareness service adds awareness data (online status and attributes) about the user.

STGroup
STGroup represent a Sametime group (also know as a public group in the Sametime Connect clients) as it is defined in the directory. This object can be created in the same ways as the STUser object: search by name (resolve), browse the directory, or create from scratch.

STServer
STServer represents a Sametime server. Once a user logs into the community, the user is connected to a specific Sametime server. The STServer object can be obtained through the getServer() call of the Login object. A typical use of this object would be to monitor its attributes using the Awareness service. Server attributes are used to publish its capabilities throughout the community to all of its clients. For example, whether audio/video capability is enabled by a specific server is published as a server attribute. Clients can use this information to determine the kind of meeting capabilities supported by the current server installation.

Chapter 2. Sametime toolkit services

45

STUserInstance
STUserInstance represents a single login of a Sametime user. Once a user is logged into Sametime, he is assigned an STLoginId which is valid for the duration of the login. An application can choose to use this information, which is contained by the STUserInstance object, to contact a specific login of the user instead of relying on the server for choosing the appropriate login for it. While this information is available to the developer, we recommend not to use or rely on it due to its transient nature, as opposed to the STUser object which holds persistent information.

2.5.4 Sametime attribute types


Figure 2-12 shows the relationship of the Sametime attributes.

STAttribute

STExtendedAttribute
Figure 2-12 Sametime attributes class diagram

Attributes are used widely in Sametime in the description of Users, Servers, and Places. We discuss the two different types of attributes here.

STAttribute
STAttribute is the basic definition for a Sametime attribute that is comprised of two parts: Key: A number associated with the attribute. Well-know keys are allocated and managed by Sametime. Value: Any type of data associated with the attribute (text, image, binary).

STExtendAttribute
STExtendAttribute extends the basic attribute with support for heavy and existential attributes:

46

Working with the Sametime Client Toolkits

Heavy attribute is an attribute that has a content, but the content was not delivered as part of the attribute. In the case of a heavy attribute where the content is not available as part of the attribute, the application must specifically call on the service supplying the attribute to get its content. This functionality is used in places where attributes may contain large quantities of date (images) that is delivered to a large number of users. In order not to overload the network, the content is delivered only upon specific demand from the application. (See the following method in the toolkit reference guide: WatchList.queryAttributeContent()). Existential attribute is an attribute that does not have any content associated with it. This attribute serves as a marker and is used as a boolean flag indicating the existence or nonexistence of a certain property. Identifying an existential attribute is done via the STExtendedAttribute.isExistential() method. For example, a server attribute indicating whether directory browsing (Directory Service) is supported by the server is marked as an existential attribute. If the attribute exists, then the server supports directory browsing, otherwise not. This concludes our discussion of the Sametime core types.

2.6 Summary
In this chapter we have discussed how Sametime uses an event model, and how the Sametime toolkit offers proxy objects on the client side that the developer can utilize in developing collaborative applications. The Sametime toolkit model contains many interfaces, and we discussed the relationship between events, interfaces, listeners, and adapters. Then we gave an overview of the different services offered by the Sametime client community toolkits. We looked at the basic things you must do in any Sametime program, and finally we explained what the core types in Sametime are. Even though you may never handle any of the core types directly, they are involved in all Sametime functionality.

Chapter 2. Sametime toolkit services

47

48

Working with the Sametime Client Toolkits

Chapter 3.

Places architecture
The Sametime places architecture provides a flexible and robust model that supports place-based awareness and collaboration. In this chapter we examine the basic concepts of this architecture and see how they can be combined to create rich real-time applications. The topics covered are: The Sametime places model with virtual places, sections, activities, and attributes Communication in a place - sending messages or changing attributes The Places API - toolkits Examples of doing things in a place In addition to the place-based samples in this book (in Chapter 6, A place-based auction example on page 101 and Chapter 9, A complex meetings sample on page 207), we encourage you to take a look at the more detailed technical documentation that is provided with the Sametime toolkits as well.

Copyright IBM Corp. 2002. All rights reserved.

49

3.1 What can I do in a Place with the client toolkits


A Sametime virtual place is the perfect place for people to meet in real time, no matter where they physically are located. You can use a place to see who else is here. You can exchange text and data messages and initiate other one-on-one sessions with other place members or you can simply monitor them. Users in a place, as well as the place itself and the sections in it (all called place members), can have attributes. A place can also have activities (which we discuss later in this chapter) and these activities can also have attributes. You can monitor attributes to get information about the other place members and you can share information about yourself by setting attributes. You can move around between sections in the place, and depending on how you enter the place you can broadcast messages to all other users in the place or to all users in your own section. If you create a place with a client toolkit, it always contains three sections: a section called stage and two non-stage sections. Users in the stage section have more capabilities than other users. A place can also have activities. Comparable to what servlets can do on a Web application server, think of activities as servlets for places. Using the client toolkits you cannot create your own activities, but Sametime comes with built-in activities like audio and video. If you add these activities to your place, you can use audio and video (in addition to text and data) to communicate with other place members. While you cannot add sections or activities with the client toolkits, the architecture does not impose such limits. The Sametime Community Server Toolkit allows you do these things and much more. We discuss this in the Redbook Working with the Sametime Community Server Toolkit, SG24-6667. However, as we explore in some of the samples in this book, you can still create very powerful place-based applications with the client toolkits. We now describe the capabilities of the Sametime Place architecture in more detail.

50

Working with the Sametime Client Toolkits

3.2 Place-based awareness and collaboration


Place-based awareness allows users to be aware of the online status of users that are in a virtual place. The concept of virtual places has now been established as a fundamental concept among the community of real-time messaging and collaboration developers throughout the world. It provides the ability to group users according to some sort of property they share, thus having a way to treat them as a whole. Adding collaborative abilities further enhances the power of that technology by allowing users to exchange information and take part in various activities while in a virtual place. Figure 3-1 shows the Sametime meeting room client that uses the Places architecture.

Figure 3-1 Sametime meeting room client

Let us look at the object model for Sametime places.

3.3 The Sametime Places model


Figure 3-2 on page 52 show the place objects supplied by the Sametime Places service and how Sametime users relate to these objects.

Chapter 3. Places architecture

51

Figure 3-2 The Sametime Places model

We will now look at places, sections, activities and attributes.

3.3.1 Virtual places


A Sametime virtual place is an abstraction of a meeting place in which users collaborate in various activities. Formally speaking, a place is a shared property of a group of users and activities. A virtual place is defined by its name, so anything that can be represented as a string can be a place. The most common examples are Web pages (URLs), discussion databases (using the Document ID), or a randomly selected string for an instant meeting. Once such a virtual place is created, all the users that enter that place can: Be aware of the online status of each other Communicate in a number of ways Take part in different activities that run in that place There are two types of virtual places that can be created in Sametime: a persistent place and a non-persistent one. A persistent place is a place that exists regardless of the existence of users inside it. A non-persistent place is created when the first user enters it and is destroyed a short time after the last user has left. Scheduled meetings are examples of when it is appropriate to use

52

Working with the Sametime Client Toolkits

persistent places; non-persistent places would be more appropriate for instant meetings (like in Sametime connect client). Although in this context persistent means that you avoid the place being destroyed when there are no more users in it, a persistent place will not survive a server restart.

3.3.2 Sections
In the Sametime places model, a virtual place is made out of sections. This makes the place similar to a natural place that has different rooms inside it. Every user that enters a place enters a specific section in that place (just as, when entering a real place, you actually enter a specific room in that place). This is very useful; for example, an event-hosting application such as an auditorium could separate the audience from the presenters by putting them into different sections. The concept of sections further enhances the awareness and communication capabilities inside a place by adding the notion of scope. Using the same example, the audience can communicate among themselves without having the presenters hear them, and vice versa. Or, one might want to have the audience be aware of the online status of the presenters only, and not of each other. This is possible due to the fact that sections are treated in the places architecture just like any other place member, which means that they can be communicated with in the ways described in the following sections. A special section in the place is entitled the Stage. A user in the stage has more permissions than others. For example, he can talk to the entire place, not only to other users in his section. For the full list of permissions in a place see Table 3-1 on page 55.

3.3.3 Activities
Activities are server-side applications that share the place with the users and define ways in which they can collaborate. Think of activities as servlets for places. Taking the auditorium example again, one might want to add an audio or video activity to the auditorium place to make the presentation more fluid. Activities are treated in the places model just as other place members (users). They can communicate with users and with each other in exactly the same way. As opposed to users, though, activities are very powerful in terms of permissions. One might think of an activity as a super user in the place. For the full list of permissions in a Sametime place see Table 3-1 on page 55. The notion of activities enhances the power inside a virtual place to its maximum. Theres no limit to the things that can be done. From shared Web games to enhanced collaborative meetings, activities are everywhere. In our C++ sample Adding activities to the place on page 281 you can see an example of adding Sametime-supplied activities to a place. In the redbook Working with the Sametime Community Server Toolkit, SG24-6667 we describe how the developer can add a server-side activity to a place with an auction house example.

Chapter 3. Places architecture

53

3.3.4 Attributes
All place members have a list of properties describing them, and can also have a list of attributes. Those attributes are in a key/value format and can contain any information that the developer wishes to attach to the given member. While the properties of a member represent static predefined information of a place member and cannot be changed, a members attributes represents dynamic information about it. It should be mentioned here, as well, that attributes of place members should not be confused with other attributes in Sametime like the Online attributes of Sametime entities and the Storage long term attributes. The places attributes exist only in the scope of a particular place and should be treated as such. Refer to the relevant toolkit documentation for further explanations of the online attributes and the storage attributes.

3.4 Communication in a place


Communication among place members (for example, users and activities) can be done in 2 ways: Direct text/data messages Using members attributes Direct communication is quite straightforward. A message can be sent to any member of the place (subject to permissions). In order to talk to all the users in a specific section, one just sends a message to that section; to talk to all the users in a place, he addresses it to the place, and so forth. Additionally, key/value based attributes can be attached to all members of the place, allowing other members to be aware of those attributes and the changes that occur in their content. Once again using the auditorium example, the presenters section can be identified by an attribute that includes its name, another attribute that contains a representable image for clients. Every presenter can have an attribute containing their picture and a list of details about themselves, and so on. Changing ones attribute can be considered as sending a message to him. The issue of using direct communication versus attributes really depends on the needs of the specific application at hand. We once again remind you not to confuse between the places attributes and other Sametime attributes. Places attributes exist only in the scope of a place and should be treated as such. Receiving messages, just like any other notification, is subject to subscription. One must subscribe to get specific events; when no longer interested, one should unsubscribe. Subscription is done by registration of

54

Working with the Sametime Client Toolkits

listeners on the objects that you are interested in. This model is similar to the standard event dispatching model used by Java technology since JDK1.1 (in the AWT and Swing libraries, for example). The benefits are obvious: it reduces the network traffic and thus enhances the performance of the system.

3.5 Permissions list


Table 3-1 lists the communication capabilities of different members of the place. There are 3 main actors: User that is in the stage section User that is on another section An activity For example, while a user on the stage is allowed to send messages to every other section in the place, a regular user (that is, a user off the stage) cannot.
Table 3-1 Communication capabilities
Action Direct messaging Directed to User Activity Section Place Attributes manipulation User Activity Section Place From user on stage Allowed Allowed Allowed Allowed Only its own Not allowed Only its own Allowed From user off stage Allowed Allowed Only to its own section Not allowed Only its own Not allowed Only its own Not allowed From activity Allowed Allowed Allowed Allowed Allowed Allowed Allowed Allowed

It should be noted that as for receiving notifications on messages or on attribute changes there are no restrictions. Any member can receive messages that are sent to him either directly or not, and can watch the changes of attributes of any other member. The restrictions only apply to active operations like sending messages and changing attributes of members.

Chapter 3. Places architecture

55

3.5.1 Access to the place and the stage section


You can limit access to the place to a specified list of users (using the addAllowedUsers() method). If you do not call this method, any user can enter the place as long as the user has the place name, type and password (if applicable). Once in the place, users can freely move between sections with one exception. A user that is on the stage section can determine who else is allowed to enter the stage section by adding a list of allowed users to the section. This way regular users can be locked out from the stage section, so only moderators, presenters, customer service agents, and so on are allowed the higher capabilities you get when you are in the stage section.

3.5.2 Places span the community


A Place is always hosted on one Sametime server. However, you can enter a place in your community no matter which Sametime server you logged into. To find out which server is hosting the place, you can use the place method called getServer().

3.5.3 Place scalability


The Place architecture is highly scalable as long as you use it the right way. It makes no sense to try and give a number of users that a place can accommodate because it depends very much on the type of application being hosted by the place. The most important thing that affects place scalability is the use of sections. If you add all your users into a single section in the place, you will not get the same level of scalability as if you spread your users out over several sections. This is because everybody has to be notified about everybody else in a section. If all users are in the same section a lot more events will be generated than when the users are spread out over several sections. While places created by a client toolkit are limited to three sections, you can create places with the Sametime Community Server Toolkit where you can add as many sections as you want and you can specify the capacity of each section. To learn more about this toolkit see Working with the Sametime Community Server Toolkit, SG24-6667.

56

Working with the Sametime Client Toolkits

3.6 The Places APIs


The Sametime places architecture is exposed to developers in several ways: The client toolkits Both the Sametime Java toolkit and the Sametime C++ toolkit expose the client side of the places architecture. Using the client toolkits, one can write applications that use places as users. Those users can create places, enter into them, and take part in the activities that go on in them. Usually they are used to write the GUI parts of an application that uses the places architecture. This is done through a component called the PlacesService. Refer to the technical documentation that comes with the client toolkits for more information. The Sametime Community Server Toolkit Sametime 3.0 introduces a server-side toolkit, which is discussed in detail in the redbook Working with the Sametime Community Server Toolkit, SG24-6667. Using the server toolkit, one can write powerful activities that enhance the place capabilities. This is done through a component called ActivityService. Another component, called the PlacesAdminService, provides administration capabilities of the places service. Using the PlacesAdminService you can: Create and destroy persistent places Use a directory of sorts that provides information on places that exist in the community Control the default behavior and characteristics of places that will be created by clients (for example, the default number of sections) For more information, refer to the documentation that comes with the server toolkit, or to the redbook referenced previously.

3.7 Examples of doing things in a place


We have explained the static and some of the dynamic place architecture in the prior sections. The application flow for a place is dependent on a number of listeners. In this section we give you some simple examples of doing something in a place that should help you understand how you must use listeners and events to work in a place. If you want to brush up on a general discussion of events and listeners, see 2.2, Interfaces and other funny words on page 23.

Chapter 3. Places architecture

57

Important: The following are only examples of how you can work with the place architecture. We are showing some sample flows that are common to many programs, but you can do much more with places than is illustrated here. Also, to keep things simple we are not covering any interaction with activities in the following samples.

3.7.1 Entering a place and listening for place events


Figure 3-3 shows the events that flow when you enter a place.

: PlaceListener

: Place

: PlacesService

createPlace(String, String, EncLevel, int, short)

addPlaceListener(PlaceListener) enter(String, short, boolean) entered(PlaceEvent)

sectionAdded(PlaceEvent) attributeChanged(PlaceMemberEvent) and so on

Figure 3-3 Entering a place and listening for place events

We assume you already have a reference to the PlacesService. To enter a place your must have an object that implements the PlaceListener interface.

createPlace
First you create a context for the place you are about to enter. The place may not even exist yet. Among the things you specify in the parameters, besides the place name, is the level of encryption you want to use for communication between your application and the place.

58

Working with the Sametime Client Toolkits

addPlaceListener
You need the context for the place before entering it because it allows you to start subscribing to events from the place. Once this has been done you can enter the place.

enter
In the parameters of the enter method you decide whether the place already has to exist, whether you want to create it or whether you dont care. You also select whether you want to enter the place in the stage section or a non-stage section. Remember that somebody else may already have entered the stage and defined a list of allowed users for the stage section. If you are not in that list and you attempt to enter the stage section, you will not succeed in entering the place. Finally, you can also supply a password for the place you are about to enter. If you are the creator if the place you will be setting the password for the place. If the place already exists, you must supply the password that was defined by the creator of the place.

entered
Upon successful entry your PlaceListener object (the one you passed as a parameter to the addPlaceListener method) receives the entered message. Once you receive this you are in the place and can start doing a lot of things. Your PlaceListener object will receive lots of other messages as well, as defined by the PlaceListener interface. For example, you will receive a sectionAdded message for section in the place, an attributeChanged message for all attributes that may exist in the Place, and so on.

You only get a message for an event once!


Just after having entered a place you will receive a lot of messages that describe the current state of the place. After that you will only receive Place events when something new happens. This means that you must make sure you get a reference to the place member object you want to work with the first time a message related to that member object arrives. For example, places created with the Sametime Java or C++ client toolkits contain three sections and new sections cannot be added. The only time you can get a reference to all sections in your place is when you get the three sectionAdded messages immediately after you have entered the place.

Chapter 3. Places architecture

59

3.7.2 Figuring out which section is which


As we just discussed, the only way you can get a reference to all three sections in your place (as created by a Sametime 3.0 client toolkit) is to listen for the sectionAdded Place event. You can get a reference to the section using the getSection() method in the event object. Once you have the section you can figure out whether it is the stage section by using the isStage() method. However, you still have two other Sections that you need to distinguish between. You can assume that users choosing to enter a non-stage section always enter the same section. In this case you can get your own section (as we show a little later in 3.7.3, Changing your section on page 61), and see which of the two sections it is equal with. The places object provides an implementation to the equals() and hashcode Java methods; it thus provides a way to compare with others and can be used within standard tables. Each section also has a member ID. We are fairly certain that the value of the stage section always is 1 and the two other sections have the values 3 and 4. Likewise, we are fairly certain that you always enter the section with member ID 3 if you decides to enter a non-stage section. However, even if it should turn out that the non-stage sections in your session may have other member IDs, you can always be sure that the IDs will remain the same during the full session and that one will be higher than the other. Thus to assign the sections to variables in your program you first identify the stage section with the isStage() method. Then you assign the two other sections to temporary variables. Once both sections are assigned to variables you can calculate which of them has the highest member ID and you can then assign them to permanent variables in your program. Here is an example of how to do it in Java:
public void sectionAdded(PlaceEvent event) { m_section = event.getSection(); if (evt.getSection().isStage()) { stageSection = evt.getSection(); } else { if (tmp1 == null) { tmp1 = evt.getSection(); } else {

60

Working with the Sametime Client Toolkits

tmp2 = evt.getSection(); if (tmp2.getMemberId().intValue() < tmp1.getMemberId().intValue()) { firstNonStageSection = tmp2; secondNonStageSection = tmp1; } else { firstNonStageSection = tmp1; secondNonStageSection = tmp2; } }

3.7.3 Changing your section


Figure 3-4 shows how you can change from one section to another in the place.

MySectionListener

: : 3 : Section MyselfEvent MyselfInPlace getMyselfInPlace( )

4 : Section

: Place

addMySectionListener(MySL) getSection( )

changeSection(Section) sectionChanged(MyselfEvent) removeSectionListener(SL) getSection( ) addSectionListener(SL)

Figure 3-4 Changing your section

Your object must implement the MySectionListener interface, you must have a reference to your place object, and you must have a reference to the section you want to move to. We discussed how to get references to all sections in a place in the previous section.

Chapter 3. Places architecture

61

You must use the object that represents you in the place (getMySelfInPlace) and you must add a MySectionListener to change to another section. You may already have a reference to your current section; otherwise, you can use the getSection() method in your MySelfInPlace object. To change the section you then simply send the changeSection message to your MySelfInPlace object and pass the new section object as parameter. The change has been successful if you receive the sectionChanged event. You can get a reference to the new section from the event by using the getSection event method. If you had a event subscription on your old section, you must remove that listener from the old section and subscribe to the new section instead.

3.7.4 Getting your section and listening for section events


To get a list of other users in your section you must first get your section. Figure 3-5 shows two variations of how you can get your current section and then start listening to it.

: PlaceListener SectionListener

MyselfInPlace entered(PlaceEvent) getMySection( )


Variation A

: Section

: Place

getSection( )
Variation B

addSectionListener(SectionListener)

usersEntered(SectionEvent) attributeChanged(PlaceMemberEvent) and so on...

Figure 3-5 Getting your section and listening for section events

62

Working with the Sametime Client Toolkits

Your object must implement the SectionListener interface, and you must at least have a reference to your place object. As soon as you have entered a place you can query your place object for your section using the getMySection Place method. Another way to do it is if you have gotten your MySelfInPlace object as described in 3.7.3 on page 61. You can then send it a getSection() message. When you have gotten your section object, you subscribe to section events by adding a SectionListener to it. You then receive events like usersEntered and attributeChanged from your section. You can also add listeners to the other sections in the place in the same manner. If you want to do this you should do it when you receive the sectionAdded Place event (discussed in 3.7.2 on page 60).

3.7.5 Getting a list of users in a section and listening to them


Once you have a section object you can get a list of users in that section by adding a SectionListener to it. Figure 3-6 shows how to do this.

: SectionListener UserInPlaceListener

array with : : UserInPlace SectionEvent

: Section

: Place

addSectionListener(SectionListener) usersEntered(SectionEvent) getUsers( )

for (int i = 0; i<users.length; i++)

addUserInPlaceListener(UIPL) )

attributeChanged(PlaceMemberEvent)

Figure 3-6 Getting a list of users in a section and listening to them

Chapter 3. Places architecture

63

Your object must implement the SectionListener interface as well as the UserInPlaceListener interface. You must have a reference to the section you want to get a list of users from. When you add a SectionListener to a section, one of the messages you will receive is usersEntered. You can then get a list of all users by using the GetUsers() method in the event object. If you are interested in a particular user, you can iterate through the list until you find the one you are looking for. If you want to monitor all users, you must add a UserInPlaceListener to each user. Once you have added such a listener you will start to receive events like attributeChanged from the users in the section.

3.7.6 Setting attributes of place, section, user


As described earlier, you can share information in the place by setting attributes for the place, for your section, or simply for yourself. Figure 3-7 shows how to do this for the different types of objects.

PlaceListener UserInPlaceListener SectionListener

: UserInPlace

: Section

: Place

changeAttribute(STExtendedAttribute) changeAttributeFailed(PlaceMemberEvent)

changeAttribute(STExtendedAttribute) changeAttributeFailed(PlaceMemberEvent)

changeAttribute(STExtendedAttribute) changeAttributeFailed(PlaceMemberEvent)

Figure 3-7 Setting attributes of place, section or user

64

Working with the Sametime Client Toolkits

Depending on which object you want to change an attribute for, your object must have an appropriate listener on it. As long as the listener interface you implement inherits from PlaceMemberListener you are safe because it defines the attribute-related events. You must have a reference to the object you want to change the attribute for (if the attribute does not exist it will be created automatically). Then you create an instance of STExtendedAttribute and populate it with a key and a value; and finally you send it off by invoking the changeAttribute method in the Place, Section, or UserInPlace object. If something goes wrong when you attempt to change the attribute, you will receive a changeAttributeFailed message. You can find the error by using the getReason() method in the PlaceMember event object. For example, you will get an error if you are in a non-stage section and attempt to change a place attribute (because you do not have permission to do this). In the next example we look at the event you receive when the change of attribute was successful.

3.7.7 Listening for changed attributes


Figure 3-8 shows how you receive notification when an attribute in the place, in a section, or for a user is updated.

PlaceMember Listener

STExtended Attribute

PlaceMember Event

: UserInPlace

: Section

: Place

attributeChanged(PlaceMemberEvent) attributeChanged(PlaceMemberEvent) attributeChanged(PlaceMemberEvent)

getPlaceMember( ) getAttributeKey( ) getAttribute( )

getInt( )

Figure 3-8 Listening for changed attributes

Chapter 3. Places architecture

65

To receive notification about changed attributes, your object must implement a listener interface that inherits from the PlaceMemberListener interface. We only show this one interface to save a bit of space. As you can see on the figure, your object receives the same type of message no matter whether it is sent from the place, from a section, or from a user. Thus it makes sense to use different listener objects for the different types of place members so you avoid having to spend a lot of code on testing simply to figure out what kind of attribute is changed. However, if it is a user the attribute has changed for, you want to get that user and you do it with the getPlaceMember method on the event object. Before getting the full attribute you may want to simply get the key of the attribute and test whether it is an attribute you are interested in. To get the value of an attribute you must first get the full attribute. Then you can get its value. The STExtendedAttribute class has different methods to get the value depending whether it is a string, an integer, or a binary value. You can also test whether the attribute is existential (contains just the key, no value) or if it is a heavy attribute, as discussed in 2.5.4, Sametime attribute types on page 46.

3.7.8 Sending messages


In addition to the use of attributes, users in a place can communicate by sending messages. Figure 3-9 on page 67 shows the different options for sending messages.

66

Working with the Sametime Client Toolkits

: PlaceListener UserInPlaceListener SectionListener

: UserInPlace

: Section

: Place

sendText(String) sendData(int, byte[]) sendFailed(PlaceMemberEvent)

sendText(String) sendData(int, byte[]) sendFailed(PlaceMemberEvent)

sendText(String) sendData(int, byte[]) sendFailed(PlaceMemberEvent)

Figure 3-9 Sending messages in a place

Even though we show the different interfaces here, your object just has to implement one of the listener interfaces that inherits from the PlaceMemberListener interface to send messages. As you can see in the figure, text or data messages can be sent to other users, to sections, or to the place. If sending the message for some reason does not succeed, your listener object gets the sendFailed message and can extract the reason for the failure from the event object. Remember that there are restrictions on who can send messages where, as we discussed earlier and showed in table format in Table 3-1 on page 55.

3.7.9 Listening for messages sent to you


You can send as many messages as you like, but it does no good if nobody is listening. If another place member has not subscribed to receive messages, there is no way you can reach that member with a message. Figure 3-10 on page 68 shows how to subscribe to messages in a place.

Chapter 3. Places architecture

67

MyMsgListener

MyselfInPlace

: Place

getMyselfInPlace( ) addMyMsgListener(MyMsgListener)

textReceived(MyselfEvent)

dataReceived(MyselfEvent)

Figure 3-10 Listening for messages sent to you

Your object must implement the MyMsgListener and you must have a reference to yourself in the place. You can then add a MyMsgListener to your representation in the place and your listener object will start to receive text and data messages. We also saw the use of MyMsgListener in 3.7.3, Changing your section on page 61 to listen for events when you change to another section. This concludes our discussion of some of the most common operations you will use when implementing an application that utilizes Sametime virtual places.

3.8 Summary
In this chapter we have given you an overview of the Sametime Places architecture. We have explained how a place is divided into sections. Users resides in sections. A place, its sections, and the users in the place can have attributes that other place members can read. Place members can also communicate by sending text or data messages. In the last part we looked at examples of common operations in a place. We discussed the involved objects/interfaces and the event flow.

68

Working with the Sametime Client Toolkits

Part 2

Part

Java toolkit

Copyright IBM Corp. 2002. All rights reserved.

69

70

Working with the Sametime Client Toolkits

Chapter 4.

Installation and setup


To do Sametime Java development you need a tool with the correct setup. This chapter explains what you need to modify, compile, and test Sametime programs. We go step by step through: How to get the Sametime Java toolkit Using the Sametime Java toolkit with the IBM Java Development Kit (JDK) 1.3 Using the Sametime Java toolkit with IBM VisualAge for Java 3.5/4.0

Copyright IBM Corp. 2002. All rights reserved.

71

4.1 Installing the toolkit package


The Sametime 3.0 Java Toolkit is installed automatically when you install the Sametime 3.0 server. You can access the toolkit pages that include the Toolkit documentation, samples, and binaries by following these steps: 1. Browse to the home page of your Sametime 3.0 server (http://<your_Sametime_server_name>). 2. Click the Toolkit link at the bottom of the page. You might need to scroll down the page to see the link. 3. Click the Java Toolkit link on the Toolkits page. You are now at the Sametime 3.0 Java Toolkit home page. You can try out compiled versions of the supplied toolkit samples right off the server. The only requirement is that you first create test users with the names Tom, Dick, and Harriet and the password sametime. This is needed because these names are hard-coded in some of the HTML files that launch the samples. However, we also describe how to download the toolkit files so we can do our own customization to the samples instead of running them off the server. 4. You can then select to download zip files with the following content: Toolkit binaries All samples Javadoc reference Only the toolkit binaries are required, but we do recommend that you get all three packages. We also use of the Sametime samples to verify correct installation of the Java JDK. Once you have obtained the toolkit you need to extract the files. 5. Create a folder to unzip the toolkit files to. We used the following directory structure: C:\STDev\STJava for the toolkit binaries (STJava.zip) C:\STDev\STJavaSamples for the toolkit samples (STJavaSamples.zip) C:\STDev\stjavadoc for the JavaDoc files (stjavadoc.zip)

72

Working with the Sametime Client Toolkits

Table 4-1 Description of major toolkit binary files


Module CommRes.jar (and cab) STComm.jar (and cab) Description Includes text and graphic resources used by some of the UI elements in the other toolkit packages. Includes the classes that support Community Services. Sametime Community Services provide key community functionality, such as People Awareness, Places, Place-Based Awareness, Instant Messaging, and Chat. Includes the classes that support Meeting Services. Meeting Services provide real-time collaboration services for meetings. Most Meeting Services rely on Community Services and provide AWT components to render the different activities they represent.

STMeeting.jar (and cab)

Also included are other packages to provide support for broadcast clients in Microsoft Internet Explorer or Netscape, as well as Windows platform support for application sharing. Refer to the Sametime 3.0 Java Toolkit Developers Guide for more information about these packages. This document is delivered as a PDF file together with the Sametime 3.0 Java Toolkit. Note: To look at the JavaDoc toolkit documentation, open your browser to the file index.html in the directory where you unpacked the JavaDoc file; in our case the path was: C:\STJava\doc\index.html It is a good idea to bookmark this file in your browser. You can also read this documentation directly from the Sametime server. Look under the Toolkits link. That is it. You now have the Sametime toolkit files installed. What to do next depends on which Java development environment you use. Among the tools we used for our development were VisualAge for Java Enterprise Edition V3.5 and V4.0. However, the Sametime Java API works in any standard development environment that supports JDK 1.1. For those readers who do not have VisualAge for Java or another full-blown Java development environment we first describe how to install and set up the IBM Java Development Kit 1.3. This kit allows you to make modifications to the provided samples, to compile the changed source files, and to verify that they run on your system.

Chapter 4. Installation and setup

73

Note: If you have VisualAge for Java you do not need to install the IBM JDK 1.3, so you can jump right ahead to 4.3, Setup of IBM VisualAge for Java on page 79.

4.2 Installing the IBM JDK


There are several places from which you can download a Java Development Kit (JDK). If you dont have it already, we recommend downloading it from the IBM developerworks Internet site:
http://www.ibm.com/developerworks/java

Select the IBM Developer kit link. At the time of writing you can select between the JDK 1.1.8 and the JDK 1.3 (as part of WebSphere preview technologies). We chose to install the Developer Kit package for IBM JDK 1.3 (although the Sametime Java toolkit supports JDK 1.1, it will run on the 1.3 platform as well). The JDK is free, but you must register and accept a license agreement to get it. Once you download the JDK, install it. During the installation you will be asked if you want to install the runtime environment as the system JVM. We answered yes to this, and used default values for all other options. If you chose to install the runtime environment as the system JVM, you can verify correct runtime installation by running one of the sample programs. We tried to run a sample from the JDK demos with the following command from a command prompt window:
C:\Program Files\IBM\Java13\demo\sound>java -jar JavaSound.jar

However, to compile Java programs (and if you chose not to install the runtime environment as the system JVM) you need to set up the program path and class path on your machine. See the readme.devkit.ibm.html file for instructions on how to do this. It varies slightly depending on which version of Windows you are running. In the following we describe what we did for Windows 2000.

4.2.1 Setting up the path and classpath variables


Your operating system must know where the Java compiler (with the file name javac.exe) is located to compile Java programs. If you have accepted the default values during installation of the JDK, the compiler will be located in the directory: C:\Program Files\IBM\Java13\bin

74

Working with the Sametime Client Toolkits

In order for Windows to find the required Sametime classes to run and compile Java programs, you must add the toolkit jar file to the classpath variable. We placed our Sametime classes in the following directory: C:\STDev\STJava To set up the path and classpath variables on Windows 2000, do the following: 1. Go to the Start menu. 2. Choose Settings -> Control Panel -> System. Note: Depending on how your system is set up, you may have to open the Control Panel and then double-click the System icon instead. 3. Choose the Advanced tab in the System dialog window. 4. Click the Environment Variables button, then you will get a new window. 5. In the System Variables section find the variable called Path. 6. If you are unable to find the variable, click the New button. If you are able to find the path variable, select it by clicking it, and then click the Edit button. 7. In the variable value section, add a period followed by a semicolon .; then add the full path of the jar file name. For example, if the javac.exe file is located in the default directory, then the following should be included in your path:
.;C:\Program Files\IBM\Java13\bin;

8. Click OK to save your new path. 9. Next, in the System Variables section, find the variable called Classpath; select it and click Edit. 10.In the variable value section, add the full path of the Sametime toolkit jar file names. For example, if the jar files are located in C:\STJava directory, then the following should be added to your classpath:
C:\STDev\STJava\STComm.jar;C:\STDev\STJava\CommRes.jar;C:\STDev\STJava\STMe eting.jar;C:\STDev\STJava\MeetRes.jar;

Depending on what you are developing, you may also have to add some of the other jar files that are included with the Sametime toolkit. 11.Click OK to save your new classpath; click the next OK button to close the dialog for environment variables, and finally, click OK to close the System dialog window. You are now ready to test whether you can compile a Java program with the JDK.

Chapter 4. Installation and setup

75

4.2.2 Compiling and running a JDK sample


To make sure that the JDK is installed and set up correctly, we will try to compile and run one of the JDK sample programs first. 1. Open a command prompt window and change to the following directory: C:\Program Files\IBM\Java13\demo\sound\src 2. Compile the sample program in the file named Groove.java with this command:
javac Groove.java

3. Then try and run your newly compiled program with this command:
java Groove

If the program runs all right a window will open where you can experiment with the creation of different rhythms. If you did not succeed, go back and verify that you have installed the JDK as described in the file readme.install.ibm.html that is part of the JDK. Also make sure that you have set up your path and classpath statements correctly. We are finally ready to touch some Sametime code.

4.2.3 Compiling and running a toolkit sample with the JDK


In our quest to verify correct installation and setup of Java JDK and Sametime toolkit files, we now try to compile and run the ChatUIApplet sample supplied with the Sametime 3.0 Java toolkit. You can go through most of this verification without having a Sametime server running. Not seeing any error messages is sufficient for most of the journey. However, to really see that the compiled applet runs you need a Sametime server to connect to. In the following we assume that you have a Sametime server you can use for testing. The sample applet program assumes that it is being launched from a Sametime server. We will modify it so the Sametime server name can be specified as a parameter. We also need to modify the Java security policy for our computer because applets are, by default, only allowed to connect to the machine they were launched from. But first modify and compile the sample program using the following steps: 1. Open a command prompt window and change to the directory named ChatUIApplet under the directory that holds all the Sametime samples. In our case the path was:
C:\STDev\STJavaSamples\ChatUIApplet

2. Open the HTML file that is used to launch the sample applet:

76

Working with the Sametime Client Toolkits

notepad ChatUIApplet.html

The appletviewer from the JDK that we will use for testing reads necessary parameters from the HTML file. Update the file like this: a. Find the lines with parameters being passed to the applet. Add a line similar to this:
<PARAM NAME='serverName' VALUE='gefion.lotus.com'>

Our Sametime server was named gefion.lotus.com. Replace that name with the name of your Sametime server. b. Change the values for the archive and cabinet parameter so they point to where the Sametime toolkit jar files are stored on your computer. Here are the values we used:
<PARAM NAME='archive' VALUE='../../STJava/CommRes.jar,../../STJava/STComm.jar'> <PARAM NAME='cabinets' VALUE='../../STJava/CommRes.cab,../../STJava/STComm.cab'>

The lines must not wrap in real life. c. Finally, if you do not have a user named Tom with a password of sametime defined on your server, either register that user or update the HTML file to use another loginName and password. d. Save and close the HTML file. 3. Open the Java sample source file with notepad:
notepad ChatUIApplet.java

Now modify the java code to read the server name as a parameter being passed on to it. a. Locate the following line:
String serverName = getCodeBase().getHost().toString();

b. Replace it with this line:


String serverName = getParameter("serverName");

c. Save and close the Java source file. 4. You are now ready to compile your updated applet. Run this command:
javac ChatUIApplet.java

If you get any error messages, make sure that the classpath is correct. If you did not get any error messages, you can compile Sametime programs on your computer. The next question is whether you can run them. To test applets on our own machine we needed to update the Java security policy.

Chapter 4. Installation and setup

77

5. To update the Java security policy for your machine change to the following directory:
C:\Program Files\IBM\Java13\jre\lib\security

6. Open the policy file in the notepad:


notepad java.policy

In this file we can control security in a granular fashion. However, to make things easier for testing we will allow everything. 7. Insert the following line in the grant section of the file:
permission java.security.AllPermission;

Save and close the file. Note: This change to the java.policy file disables all Java security mechanisms. Do not use this on any computer that runs application in production. Use it only for development purposes. We are about ready to test the new applet. 8. Change back to the sample directory:
C:\STDev\STJavaSamples\ChatUIApplet

9. Run the appletviewer with this command:


appletviewer ChatUIApplet.html

You should now see a window that allows you to type in the name of a person you want to chat with and then an invitation to that person. If you did not get this result, retrace the steps in this chapter until you find out what went wrong.

78

Working with the Sametime Client Toolkits

Note: If your application consists of more than one class, it makes sense to gather all your classes in zipped format in a jar file that can be downloaded to the Web browser by one transfer. You use the JAR program to create a jar file. Open a command line; enter JAR and press Enter and you will be shown help for the JAR command. For example, to create a jar file named myapp.jar that contains all files in the current directory, you can use the command:
jar -cvf myapp.jar *.*

If your jar file contains a Java application (and not an applet) you may have to edit a file called the manifest file for the jar file to specify which class is the main class. You can read more about jar and manifest files in the documentation that comes with the JDK. This concludes our simple compile and run verification test. The next section is about how to set up VisualAge for Java for Sametime development. Note: If you want to use the JDK or another Java development environment other than VisualAge for Java, you can skip the remainder of this chapter and turn to Chapter 5, Introduction to Sametime Java applets on page 89.

4.3 Setup of IBM VisualAge for Java


Among the tools we used for our development were VisualAge for Java Enterprise Edition V3.5 and V4.0. Here we describe how we set VisualAge for Java 3.5 up for Sametime development, but these instruction are valid for VisualAge for Java 4.0 as well. We assume that you have downloaded the Sametime Java toolkit files as described in 4.1, Installing the toolkit package on page 72. We also assume that you already have VisualAge for Java installed. If not, you can accept all the default settings during the installation. The following descriptions are based on a default VisualAge for Java 3.5 Enterprise Edition installation.

4.3.1 Importing the Sametime toolkit files into a project


We are now ready to import the parts of the toolkit API we want to work with into VisualAge for Java 3.5. We will not utilize the Sametime meeting services in our Java samples in this book, so we will only import the packages STComm.jar and CommRes.jar. If you want to try out all the toolkit samples or develop applications with meeting functionality, you should import all the toolkit binaries.

Chapter 4. Installation and setup

79

1. Open VisualAge for Java and go to the Workbench window. In the Workbench window, with your mouse, right-click to receive a popup menu and select Add -> Project. 2. Select Create a new project named: and enter the name of the new project that will receive the Sametime API classes. We used Sametime Comm Toolkit. Click Finish to create the new project. 3. In the Workbench window you should see the newly created project. Select the Sametime Comm Toolkit project. Right-click to get the popup menu and select Import. 4. You will be presented with a dialog where you can specify how to import the Java code. Select Jar file and click Next. 5. You should now see a dialog where you can specify the location of the jar file you want to import. Click the Browse button and maneuver to the directory that you extracted the Sametime 3.0 Java API into; in our case it was C:\STDev\STJava. Select STComm.jar and click Open. 6. Check the class check box. You can try to click the Details button associated with the class check box. This displays a dialog where you can see which class files will be imported. All files should be selected, but to make sure click the Select all button to select all the classes within this jar. When done, click the OK button to return to the previous screen. 7. Make sure that the Project text box contains the name of the project we will be importing the jar files classes into. For us this project is Sametime Comm Toolkit. If the project name does not exist in the text box, click the Browse button and select the project to import the classes into. 8. Click Finish to commence the import process. You will be presented with a status bar indicating the progress of the import. 9. Repeat the previous steps for the CommRes.jar file located in the directory we extracted the Sametime Java API into. This file only contains resources, so while the class check box can be selected the important thing is that the resources check box is selected. Once you have imported all the classes and resources into your project, your VisualAge for Java Workbench should look something like that shown in Figure 4-1 on page 81.

80

Working with the Sametime Client Toolkits

Figure 4-1 VisualAge for Java workbench with projects

Importing the Sametime samples


The Sametime samples are not supplied in a jar file, so you import them a little bit differently. We describe the procedure briefly here. First you must create a project for your samples. We called our project Sametime samples. Follow the same procedure for creating a project as described in the previous section. Then do the following to import the sample: 1. In VisualAge, select the project you want to import the sample program to. We used the project Sametime samples. Right-click to get the popup menu and select Import. 2. You will be presented with a dialog where you can specify how to import the Java code. Select Directory and click Next. 3. You should now see a dialog where you can specify the location of the directory you want to import from. Click the Browse button and maneuver to

Chapter 4. Installation and setup

81

the directory that you extracted the Sametime 3.0 Java API into; in our case it was:
C:\STDev\STJavaSamples\CustomizeChatUI\

Click OK to return to the Import dialog. 4. The samples come as source code, so instead of the class check box we select the java check box as well as the resources check box. If you click the Details button associated with the Java check box you can see that three java files are targeted for import. When done, click the OK button to return to the previous screen. 5. Make sure that the Project text box contains the name of the project you will be importing the jar files classes into. For us this project was Sametime samples. If the project name does not exist in the text box, click the Browse button and select the project to import the classes into. 6. Click Finish to commence the import process. You will be presented with a status bar indicating the progress of the import. The imported applet will be placed in the default package for the project. You can change this if you want, but the default location is fine for our purposes. Before you can give the Sametime applet a test run there are a few additional things you have to do. To test a basic applet in VisualAge you can right-click on the project for the applet and select Run->In Applet Viewer from the popup menu. You should now be able to view your applet running within VisualAge for Java. However, if some code that your applet uses is in a project other than the one currently selected, you need to make sure that the classpath has been set correctly. For Sametime applets you also need to make sure the Java security settings on your computer allow testing them since they will access another machine. We discuss this in the following sections.

4.3.2 Setting up the classpath in VisualAge


As we discussed in the previous section, importing the Sametime 3.0 Java Toolkit into VisualAge for Java 3.5 is the first step in creating applets that implement the Sametime 3.0 functionality. Once you have created an applet that uses this toolkit, you need to configure the applets classpath to ensure that it sees the correct classes when you want to test your application from within VisualAge.

82

Working with the Sametime Client Toolkits

To accomplish this, follow these steps: 1. In the Workbench, select the applet that you wish to execute (in our case CustomizeChatUI) and right-click your mouse to obtain the popup menu. Select Properties and a dialog window opens. If it is not already selected, click the Class Path tab and you will be presented with a dialog similar to Figure 4-2 (except that we have not specified project path yet).

Figure 4-2 Applet properties dialog

2. Ensure that the Include '.' (dot) in class path check box is checked. 3. Check the Project path check box and click the Edit button. You will be presented with a dialog with a list of all projects in VisualAge. 4. Select all the relevant projects that you require to be in the classpath for this particular project. For our example, we need the Sametime Comm Toolkit project. Select the project and click OK. 5. Click the Compute Now button to make sure your changes are reflected in the current environment. A warning will be shown. Accept to compute the new class path. 6. Finally, click the OK button to return to the Workbench window. The classpath is now set up correctly.

Chapter 4. Installation and setup

83

4.3.3 Passing parameters to the applet


Many applets, including the one we are using, have parameters passed to them when they are launched. Normally these parameters are hard-coded in the HTML file that launches the applet, but when we test in VisualAge the applet is launched directly without any HTML file. You specify parameters for an applet in VisualAge by following these steps: 1. In the Workbench, select the applet that you wish to execute (in our case CustomizeChatUI) and right-click your mouse to obtain the popup menu. Select Properties and you will again be presented with a dialog similar to Figure 4-2 on page 83. 2. Click the Applet tab. Enter the parameters in the input box on the right side. You can often copy the statements from an HTML file and then modify as needed. For the CustomizeChatUI applet we entered the following parameters:
<PARAM NAME='loginName' VALUE='Tom'> <PARAM NAME='password' VALUE='sametime'> <PARAM NAME='serverName' VALUE='gefion.lotus.com'>

Our Sametime server was named gefion.lotus.com. Note: The parameter serverName is not included in the original sample. The code assumes that the Sametime server is the same as the applet is launched from, which is not the case for us. We could hard code the server name in the code while we test, but using a parameter makes this a bit more flexible. 3. Click OK to save your new properties. We will now modify the Java code to read the server name as a parameter being passed on to it. 4. Find the init method for the CustomizeChatUI class: a. Locate the following line:
String serverName = getCodeBase().getHost().toString();

b. Replace it with this line:


String serverName = getParameter("serverName");

c. Save your changes. Now we only need one more thing before we can test the applet.

84

Working with the Sametime Client Toolkits

4.3.4 Modifying the java.policy file in VisualAge for Java


To test an applet that logs into a Sametime server, the applet is required to create a connection across a network to a computer. Java applets cannot open a connection to a computer over a network unless that computer is the origin host. The origin host is the computer that the applet was downloaded from. So, if you have developed an applet on your computer, Redbook, that is required to log into the Sametime Server named gefion.lotus.com, your applet will generate a Security Exception if you try to run it from within VisualAge for Java, since it is trying to open a connection to a computer other than the origin host. To solve this security issue we need to modify the java.policy file for VisualAge on the machine where VisualAge for Java is installed. To modify the java.policy file, follow these steps: 1. Locate the java.policy file. It is found in <VA for Java>\ide\program\lib\security where <VA for Java> is the default installation folder for VisualAge for Java. For us the path to the java.policy file was:
C:\Program Files\IBM\VisualAge for Java\ide\program\lib\security.

2. Open the java.policy file using notepad or your favorite text editor and add the following policy in the big grant section:
permission java.security.AllPermission;

When complete, the beginning of your changed java.policy file should look similar to Figure 4-3.

// Standard extensions get all permissions by default grant codeBase "file:${java.home}/lib/ext/*" { permission java.security.AllPermission; }; // default permissions granted to all domains grant { permission java.security.AllPermission;

Figure 4-3 Part of the java.policy file with a new line added

Note: This change to the java.policy file disables all Java security mechanisms. Do not use this on any computer that runs applications in production. Use it only for development purposes. 3. Save the java.policy file.

Chapter 4. Installation and setup

85

We are now ready to test the applet.

4.3.5 Running the applet within VisualAge


To test an applet in VisualAge for Java you first specify classpath, define applet parameters, and modify security settings, as described in the previous sections. You must also make sure that your Sametime server is running. Then do the following: 1. In the Workbench, select the applet that you wish to execute (in our case it was CustomizeChatUI) and right-click your mouse to obtain the popup menu. Select Run -> In Applet Viewer. 2. The applet window launches. At the same time VisualAge opens a console window. In this window you can see all the messages to system.out that are part of the sample code like this:
System.out.println("LOGGED IN");

You should now have enough basic knowledge to start working with Sametime development in VisualAge for Java.

4.3.6 Exporting the applet from VisualAge


Once you are satisfied with your applet and want to deploy it for test and production, you must export it from VisualAge. If you have an applet that only consists of one class you can export it to a directory as a compiled class file and you are done. You can also export several compiled classes to a directory at one time, but we suggest that you export an application that spans several classes directly to a jar file (which is a zip file containing compiled classes and/or Java source, and potentially, resources such as images and property files). To export the CustomizeChatUI applet as a jar file, do the following: 1. In the Workbench, select the classes for the CustomizeChatUI applet:
CustomizeChatFactory CustomizeChatUI ImagePanel

2. Right-click your mouse to obtain the popup menu. Select Export... The Export SmartGuide window opens. 3. Select to export a Jar file and click Next. 4. Specify a file name for the jar file, for example:
custui.jar

86

Working with the Sametime Client Toolkits

Make sure there is a check mark for .class and resource. It is optional whether you want to export the Java source as well. 5. Click the Details... button for resource. A new dialog named Resource Export opens. 6. Select the Sametime samples project in the left list box and make sure that logo.gif is selected in the right list box. Click OK to return to the SmartGuide window. 7. You can select to have an HTML file to launch the applet generated automatically by VisualAge. To do this set a check mark next to .html. The parameters we entered for the applet class in VisualAge are used to create the HTML file. 8. Finally, start the export by clicking the Finish button. The compiled classes and the logo.gif file are exported to the custui.jar file and the HTML file is created in the same directory. That is it. You can move your jar and HTML files to a directory under the Sametime server. You may have to edit the archive statement in the HTML file to include the Sametime toolkit jar files (STComm, CommRes.jar, STMeeting.jar, MeetRes.jar, and so on). Once you have done this you are ready to test your applet in the real world!

4.3.7 The resource not found problem


In some situations in the past we had problems testing the Sametime toolkit samples from VisualAge for Java if the toolkit resource files (CommRes) and the sample applet were in different projects. However, we found out that when we modified the java.policy file as described in 4.3.4, Modifying the java.policy file in VisualAge for Java on page 85 to allow everything we did not have this problem. Earlier we had applied more granular changes to the java.policy file.

4.4 Summary
In this chapter we have discussed how you get the Sametime Java client toolkit, and how you set it up, develop, and run programs using the IBM JDK 1.3. We have also gone through the same exercise for VisualAge for Java.

Chapter 4. Installation and setup

87

88

Working with the Sametime Client Toolkits

Chapter 5.

Introduction to Sametime Java applets


The samples from the Sametime Java client toolkit in this book are all applets. Before we look at the samples we will take you through a few basic things about how Sametime applets work.

Copyright IBM Corp. 2002. All rights reserved.

89

5.1 Sametime applet basics


We will walk you through the first steps of every Sametime application, in this case, a Java Applet. A Java Applet may implement the four basic methods: init(), start(), stop(), and destroy(), which are called by the browser. We use these events to organize our Sametime-related activities. Note: For some applications you may not use an applet for implementation, and Sametime does not require this. For instance, you can implement a servlet to perform Sametime actions. Follow these guidelines to ensure that your application can use Sametime properly: Use the logic we describe in init() for one-time initialization of your application. Use the code from start() next. The login can be performed when you need it. The Sametime listeners/events can be used unchanged. You may find some applet-related dependencies in almost any sample code which is either UI-related (you have to change this anyway) or uses applet-specific methods (which you have to implement differently), like: getParameter() - used for reading applet parameters getCodeBase().getHost() used to automatically determine the Sametime server host the applet was loaded from When the application finishes its activity, use the code from stop() and destroy().

5.1.1 QuickStart Class


First, we deliver the class source. In Example 5-1 you see a minimum of imports and that the class is derived from Applet. In case your Applet is supposed to work in environments with proxy servers, especially proxy.PAC files, you should inherit from STApplet instead, as this gives your applet support for this. You see also that we implement the LoginListener, as we need this to know if a login was successful. The members m_session and m_comm store the Sametime session and community services object references as described in the following sections.
Example 5-1 QuickStart Class
import com.lotus.sametime.community.*; import com.lotus.sametime.core.comparch.*;

90

Working with the Sametime Client Toolkits

import java.applet.*; /** * Sample Sametime Applet<p> * Introduces basic Sametime functionality */ public class QuickStart extends Applet implements LoginListener { protected STSession m_session; protected CommunityService m_communityService; }

5.1.2 init()
The init() method is called by the browser when an applet is prepared, but not yet shown to the user. The applet can prepare itself now. The code for the init method is in Example 5-2 on page 92. All Sametime applications need a session. It provides a central place to register and locate component/services on the client application. Since this object needs to be created only once, we do this in the init() method shown in Example 5-2. The session object is created with a unique String identifying it. Then all components are loaded: here you can optimize by loading only the required components and thus reduce the toolkit size. Among the components loaded by the loadAllComponents method is one called STBase. This component is the one that is responsible for communication with the Sametime server, which obviously makes it a required component for all Sametime applications. Finally, the session is started. Note about the Java Toolkit: When the services objects are created and activated, they are actually dynamically loaded from the codebase. This means that you can optimize your application download size by providing only the classes needed. The loadAllComponents method you see in Example 5-2 will simply skip components that it cannot find, so you do not need to change your application even though you have repacked the Sametime toolkit jar(s) downloaded together with your applet.

Chapter 5. Introduction to Sametime Java applets

91

Example 5-2 QuickStart init() method


/** * Applet initialized. <p> * Create the session, load all components, start the session */ public void init() { try { m_session = new STSession("SametimeQuickStart " + this); m_session.loadAllComponents(); m_session.start(); } catch (DuplicateObjectException e) { e.printStackTrace(); } }

5.1.3 start()
The start() method is called when the applet is becoming active, for instance, visible to the user. After a session is created, it will be used to create certain Service objects. Services can be proxy objects to server-side implemented services, or just utilities which act on the client side only1. The first service we have to create is the CommunityService. It provides basic functions like authentication. If your application needs other services, we suggest that you just add the service creation to the start() method of your applet. See 2.3, Sametime services: What can I do with them on page 29 for a description of Sametime services. Until now, the application has not yet talked to the server, and no network connection has been created, so the session object and the community service object are not very useful. Lets log into the server and get ready to receive events. Before logging in, we need to register for the login events.

It is not important to know this for the function of the application, but it may be important to know when you optimize your application and want to know if events traverse the network or not.

92

Working with the Sametime Client Toolkits

Example 5-3 QuickStart start() method


/** * Applet started.<p> * Create the community services<p> * Subscribe the LoginListener interface. * Login to the community using the user name and password * parameters from the html. */ public void start() { m_communityService = (CommunityService) m_session.getCompApi(CommunityService.COMP_NAME); m_communityService.addLoginListener(this); m_communityService.loginByPassword( getParameter("sametimeServer"), getParameter("loginName"), getParameter("password")); }

5.1.4 stop()
The stop() method is called by the browser when the applet is becoming inactive. We use this to log out of the Sametime server.
Example 5-4 QuickStart stop() method
/** * Applet stopped. <p> * Logout */ public void stop() { if (m_communityService != null) m_communityService.logout(); }

5.1.5 destroy()
The destroy() method is called when the applet is destroyed and has to free all resources. We close and unload the session object.
Example 5-5 QuickStart destroy() method
/** * Applet destroyed.<p> * Stop and unload the session.

Chapter 5. Introduction to Sametime Java applets

93

*/ public void destroy() { if (m_session != null) { m_session.stop(); m_session.unloadSession(); } }

5.1.6 Using the LoginListener interface


We will use the events of the interface LoginListener now. The first event our applet should receive is the loggedin() event for a successful login. We also might receive a loggedout() event instead, meaning that the login was unsuccessful. There can be various reasons: a wrong password, a problem establishing a connection, or just an unavailable server. Also, at any time later the loggedout event can happen, either because we logged out by ourselves or the connection to the server was lost. As you see in Example 5-6, we just write to the system console that the events arrived. We suggest doing this first with any interface you implement.
Example 5-6 LoginListener implementation
/** * We logged in successfully * * @param event LoginEvent The event object */ public void loggedIn(com.lotus.sametime.community.LoginEvent event) { System.out.println("Logged In"); } /** * We were logged out for some reason * * @param event LoginEvent The event object */ public void loggedOut(com.lotus.sametime.community.LoginEvent event) { System.out.println("Logged Out"); }

This concludes our walkthrough of the code in a basic Sametime applet.

94

Working with the Sametime Client Toolkits

If you try and run the supplied applet in a browser, you will not get much excitement out of it since the applet does not have any user interface. However, you can still verify that the applet actually works by opening the Java console for your browser. Once the applet has logged successfully into Sametime, it writes this information to the console, as you can see in Figure 5-1.

Figure 5-1 QuickStart applet writing to the Java console in the browser

In the following section we discuss how to extend our applet to have the user enter a Sametime place.

5.2 Entering a place


We have implemented a minimum sample applet using the places service to discuss it here. The PlaceQuickStart you see in Example 5-7 is just inherited from QuickStart, and all it does is try to enter a place.
Example 5-7 PlaceQuickStart class source
import com.lotus.sametime.places.*; import com.lotus.sametime.core.constants.EncLevel; /** * A minimum place sample * */ public class PlaceQuickStart extends QuickStart implements PlaceListener, MyMsgListener

Chapter 5. Introduction to Sametime Java applets

95

{ protected PlacesService m_placesService; protected Place m_place; protected MyselfInPlace m_mySelf; }

We implemented start() and stop() again to reflect the new service used, as shown in Example 5-8.
Example 5-8 PlaceQuickStart applet methods
/** * Applet started.<p> * Create the places service */ public void start() { m_placesService = (PlacesService) m_session.getCompApi(PlacesService.COMP_NAME); super.start(); } /** * Applet stopped. <p> * Logout */ public void stop() { if (m_place != null) m_place.leave(0); super.stop(); }

We have to override loggedIn() to create the place object.


Example 5-9 PlaceQuickStart loggedIn() method
/** * We logged in successfully<p> * Create the place object, add listener and enter the place. * * @param event LoginEvent The event object */

96

Working with the Sametime Client Toolkits

public void loggedIn(com.lotus.sametime.community.LoginEvent event) { super.loggedIn(event); m_place = m_placesService.createPlace( "SamplePlace", "Sample Place", EncLevel.ENC_LEVEL_DONT_CARE, 0); m_place.addPlaceListener(this); m_place.enter(); }

The first new interface PlaceListener brings a lot of methods to be implemented. We implemented all these methods to write to the system console. In Example 5-10 you see only entered() as this will be important for any application to listen for. We add the applet as a MyMsgListener to the place to inform us about any place-related messages. As you will see on the console, there will be other events arriving when a place is entered. Sametime informs the application about the place entered automatically. To keep things simple we use our applet class as the listener, but as your application grows you may consider outsourcing the listener responsibility to an independent adapter class, as we discussed in 2.2.4, Adapter on page 26.
Example 5-10 PlaceQuickStart: entered()
/** * entered<p> * Listen for incoming messages<p> * Send a message to the place */ public void entered(PlaceEvent event) { System.out.println("entered"); m_mySelf = m_place.getMyselfInPlace(); // Listen for incoming messages. m_mySelf.addMyMsgListener(this); m_place.sendText("Hello, place!"); }

Chapter 5. Introduction to Sametime Java applets

97

The second new interface is the MyMsgListener interface which will be called when messages (text or binary data) arrive. We just show the message on the transcript.
Example 5-11 PlaceQuickStart: textReceived()
/** * textReceived<p> * We received text from a place member */ public void textReceived(com.lotus.sametime.places.MyselfEvent event) { System.out.println("textReceived: " + event.getText()); }

The code in this chapter is a bare-bones place application example. It will not give you much joy on its own, but if you use it together with the Auctioneer client program we develop in the next chapter, you should be able to see the code working by utilizing the browsers Java console again.

5.2.1 STError: If something goes wrong


If our client for some reason cannot enter a place, the enterFailed event message is sent to our applet. We can get a reason code explaining the failure from the event object. The reason code is an integer and it should match one of the STError constants provided by the Sametime toolkit. To use the STError constants we must import their package in our class like this:
import com.lotus.sametime.core.constants.STError;

Then, in the listener method for the failed event, we can send the failure code through a switch where we test it against the possible error for that type of error message. In Example 5-12 you can see an example of how to figure out why entering a place fails.
Example 5-12 Testing why entering a place failed
public void enterFailed(PlaceEvent event) { switch (event.getReason()) { case STError.ST_ERROR_PLC_ACTIVITY_ALREADY_EXIST: System.out.println("ST_ERROR_PLC_ACTIVITY_ALREADY_EXIST "); break; case STError.ST_ERROR_PLC_ACTIVITY_NOT_EXIST: System.out.println("ST_ERROR_PLC_ACTIVITY_NOT_EXIST "); break;

98

Working with the Sametime Client Toolkits

case STError.ST_ERROR_PLC_ALREADY_EXISTS: System.out.println("ST_ERROR_PLC_ALREADY_EXISTS "); break; case STError.ST_ERROR_PLC_ATTR_NOT_EXIST: System.out.println("ST_ERROR_PLC_ATTR_NOT_EXIST "); break; case STError.ST_ERROR_PLC_DELETED: System.out.println("ST_ERROR_PLC_DELETED "); break; case STError.ST_ERROR_PLC_FULL: System.out.println("ST_ERROR_PLC_FULL"); break; case STError.ST_ERROR_PLC_INVALID_PASSWORD: System.out.println("ST_ERROR_PLC_INVALID_PASSWORD "); break; case STError.ST_ERROR_PLC_MEMBER_NOT_EXIST: System.out.println("ST_ERROR_PLC_MEMBER_NOT_EXIST "); break; case STError.ST_ERROR_PLC_NOT_AUTHORIZED: System.out.println("ST_ERROR_PLC_NOT_AUTHORIZED "); break; case STError.ST_ERROR_PLC_NOT_EXIST: System.out.println("ST_ERROR_PLC_NOT_EXIST "); break; case STError.ST_ERROR_PLC_SECTION_NOT_EXIST: System.out.println("ST_ERROR_PLC_SECTION_NOT_EXIST "); break; case STError.ST_ERROR_PLC_STAGE_NOT_EXIST: System.out.println("ST_ERROR_PLC_STAGE_NOT_EXIST "); break; case STError.ST_ERROR_PLC_TYPE_ERROR: System.out.println("ST_ERROR_PLC_TYPE_ERROR "); break; case STError.ST_ERROR_PLC_USER_ALREADY_PARTICIPATE: System.out.println("ST_ERROR_PLC_USER_ALREADY_PARTICIPATE "); break; default: System.out.println( "\n ************Failed to enter/create the place. Reason: " + Integer.toHexString(event.getReason()) + "h ************ \n\n"); break; } }

Chapter 5. Introduction to Sametime Java applets

99

Sometimes the Sametime toolkit documentation lists possible error codes associated with an event. In other situations you may look at the STError constants and determine which are relevant for the errors you want to catch. The two applets we described in this chapter are available as source code from the IBM Redbooks Web site. See Appendix E, Additional Web material on page 407 for instruction on how to get the source. To keep things simple we have just implemented one class for the QuickStart applet and another class that extends QuickStart for our PlaceQuickStart applet. However, we also include a second version called PlaceQuickStart2 where we illustrate the use of an inner class to act as PlaceEventsListener by extending the toolkit PlaceAdapter class. We discuss the advantages of using adapters in 2.2.4, Adapter on page 26 and inner classes in Using nested classes in Java as listeners on page 27. By extending a PlaceAdapter and a MyMsgAdapter in our simple case we were able to remove 18 do-nothing methods from our PlaceQuickStart class.

5.3 Summary
In this chapter we have walked through the code used to implement a basic Sametime applet. Next we extended the sample by adding the capability for our applet to enter a place and listen for messages in that place. We gave this introduction because the big sample in the next chapter is implemented with two different Sametime client applets.

100

Working with the Sametime Client Toolkits

Chapter 6.

A place-based auction example


In this chapter we walk through an example of a real-life requirement that can be satisfied with an application that leverages the Sametime Places architecture. While we look at a specific solution, many of the concepts it incorporates are of a general nature, such that you can extend them to other solution areas. First we introduce the requirement we want to address and discuss how we can do it using the Sametime Places service. We briefly discuss which objects we need in our application and how the data will flow. Then we look at the implementation of the major classes in the application, and follow that with some considerations we had when developing the application. Finally, we take you through our final application design and implementation, where you can see screen captures of the different stages in the scenario. The source code for the sample application is available for download from the IBM Redbooks Web site in the file called 6666auction.zip. See Appendix E, Additional Web material on page 407 for instruction on how to get the sample code. Included with the source code is JavaDoc for the application, as well as the full source code in HTML that you can look through with your Web browser.

Copyright IBM Corp. 2002. All rights reserved.

101

Note: We want to show usage of the Sametime community services in detail, concentrating on places. So, for instance, we do not discuss the Sametime UI components very much in this chapter. However, the Sametime Java toolkit comes with a series of well documented examples for the UI components.

6.1 Overview
Sametime virtual places are generally well suited for situations where several geographically dispersed people need to collaborate in a structured manner in real time. While we discuss a specific application in this sample, much of the implementation has general relevance. For our application we want to enable people to bid on items on line in real time. We model our solution after a traditional auction that is performed over a short period of time. The auction runs until nobody places a higher bid and the auctioneer calls 1 - 2 - sold! This is in contrast to the auctions from eBay and similar companies that model their solutions after silent auctions that run over a longer fixed period, where the winner is whoever has placed the highest bid during that period. In Figure 6-1 on page 103 you can see a basic illustration of the real life auction we want to model our virtual on-line bidding after.

102

Working with the Sametime Client Toolkits

On-lookers

Auction Item Auctioneer Bidders

Figure 6-1 An auction with bidders, on-lookers, and the auctioneer

We have an auction that consists of the following: An auction item: A thing that somebody has put up for sale. In our scenario we concentrate on what happens after the item has been commissioned to the auction house, so we do not cover any interaction with the seller. Bidders: People who want to buy the auction item. Auctioneer: The person responsible for running the auction. The auctioneer announces what is up for sale, sees who places a bid, relays the bid to all bidders and on-looker; and finally calls 1 - 2 - sold when the highest bid has been placed. On-lookers: People who are interested in following the auction, but who are not allowed to participate as bidders. The on-lookers may join the bidders group by going through some process like registration, credit check, or the like.

Chapter 6. A place-based auction example

103

We want to hold similar virtual auctions where people participating can be anywhere in the worlds, as long as they have network connectivity (and a Web browser in our first iteration). We can deduce a few of our requirements by looking at Figure 6-2.

On-lookers

Auction Item Auctioneer Bidders

Figure 6-2 Auction participants in different sections

The people participating in the auction need different rights and capabilities depending on which group (or section) they belong to. The auctioneer must be able to: See all participants Place auction items where all participants can see them. Hear all bidders Be heard by all participants Finish or stop the auction The bidders must be able to: Bid on an item See the other bidders and engage in private conversations with any of them

104

Working with the Sametime Client Toolkits

The bidders must not be able to: Broadcast messages to all participants. A bid must be passed on to the auctioneer, who then relays it to all participants. The on-lookers must be able to: Watch the bidding Join the bidders group by going through some process The on-lookers must not be able to: Place a bid All participants must be able to see the details about the auction item. There are obviously many more requirements for such an application, but we will stick with the basic ones we have listed here, and see how we can use the Sametime Places service as the underlying framework for our solution. As explained in Chapter 3, Places architecture on page 49, a Sametime virtual place contains sections. When using the Java client toolkit, a virtual place has three sections. One of the sections is called stage, and users in that section have more capabilities than users in the other two other sections. Looking back at Figure 6-2 we see that our requirements fit well with the capabilities of the Sametime virtual place. We can place our participants in three different sections that fit the three different groups of people we have identified in the figure. The first section is the stage section, where the auctioneer resides and acts from. It is access controlled, so that only the auctioneer can enter it. (Imagine a security guard protecting the stage and the auctioneer.) Remember that the stage section gives the user some additional rights, which are discussed later in this chapter. The second section is the anonymous section, where anonymous users are staying. An anonymous user is a user who logs into sametime without a password, and who can only watch the auction, but who cannot participate by bidding. The third section is the auditorium section, where the authenticated users are staying and have the option to participate in the auction by sending bids. With this design, users can enter the place after having been authenticated against the directory on the Sametime server or an LDAP directory. However, users can also enter the place anonymously. We use this to distinguish between the bidder group and the on-lookers by placing them in different sections. People who have an entry in the directory and are able to log in will be allowed to bid,

Chapter 6. A place-based auction example

105

while people who enter anonymously only are allowed to watch the auction. We will allow people in the same section to see each other and initiate one-on-one conversions via instant messaging. The auctioneer is allowed to see all participants and to initiate instant messaging sessions with anybody. Finally, there is the auction item. It does not enter the place as a user. Instead, we let the auctioneer bring it into the place and then make the auction participants aware of it through place attributes. We now discuss some of the main objects and some of the flow in the application.

6.2 Objects in the application


In this section we identify the main objects in our application. These objects are derived from the real-life objects in our scenario, as well as from the objects supplied by the Sametime Places service. We will also need some user interface objects, but they are not important for the places concept so we will skip them here and only discuss them briefly under the implementation. The real-life objects have already been well identified during our introduction. They are: Auctioneer - Responsible for starting the auction, putting item out for bid, making the sold call, stopping the auction Auction Item - An auction item is created from the following input data: Text description Picture Minimum price The auction item is a passive object. It has no responsibilities. AuctionCustomer - This can be either a bidder or an on-looker. In this iteration of the sample the capabilities of the AuctionCustomer are determined by how the user entered the auction (authenticated = bidder; anonymous = on-looker). It is possible for an on-looker to join an auction at any time by leaving the place briefly and then re-entering by authenticating with Sametime; this will assign the user to the section that contains bidders. Finally, we have the object that contains the Auctioneer, the Auction item and the AuctionCustomers: Place - The place is the object that encompasses all the other objects. The auctioneer sends information about the auction item that is up for bid by placing an auction item in the place that has the following properties:

106

Working with the Sametime Client Toolkits

Auction item title Action item URL (for location of picture file) Action item minimum price In addition the place has a property for the current state of an auction: AuctionStatus - InActive, Active, One, Two, Sold The place also contains important objects of the following class that we have not mentioned so far: Section - When a user enters a place, they also have to enter a section. Using the Sametime Java client toolkit, we have access to three sections in our place, and we put our users in different sections depending on who they are as we discussed a bit earlier. There are obviously more objects in our implementation. For example, we use an abstract class because the Auctioneer and the AuctionCustomer have much in common. We use listener objects to receive events from the place and we need some user interface objects, but the objects we have listed here are the most important ones from the business point of view.

6.3 Application flow


We now provide a high-level discussion of the application flow. We do not describe this in implementation detail, but at a level that should give you an idea of how the sample application works. We provide more detailed discussion of some of our implementation considerations later on, and you can always drill down into any topic in the sample application that interests you by looking at the supplied source code.

6.3.1 Initialization of the auction by the auctioneer


The auctioneer authenticates with the system and gets the list of items that are to be put up for auction. Then the auctioneer creates the place to be used for the current auction and enters the place in the special section that is called stage. Being in the stage section allows the auctioneer to easily send messages to all users in the place.

Putting an item up for auction


The auctioneer sets the auction status for the place to INACTIVE and fetches the first auction item from the list. The item is prepared as the next item to go under the hammer by entering its description, location of a picture of the item, and its minimum price. This data is set as attributes of the place.

Chapter 6. A place-based auction example

107

Before setting the auction status to active the auctioneer starts to listen for text and data messages from other place members. The auctioneer also locks the door to the stage section, so only users that the auctioneer specifies are allowed to enter the stage section. In our sample only the auctioneer is allowed to enter the stage section. Once this setup is done, the auctioneer starts the auction by setting the auction status place attribute to ACTIVE.

6.3.2 Entering as bidder


A bidder authenticates and enter the place that has been created by the auctioneer. In our sample, the name of the place to enter has been supplied to the bidder previously. The bidder enters the place in one of the two non-stage sections (an error will be generated if the bidder attempts to enter the stage section because the auctioneer has created an access list for that section). The bidder starts to listen to the place and thus gets information about the stage section as well as the two other sections. From listening to the stage section the bidder gets a list of all users. As we know, there is only one user in the stage section, and the bidder thus knows who the auctioneer is. The bidder also figures out which of the two other sections is for bidders. When users enter a place they can decide to enter the stage section (which the auctioneer does) or another non-stage section. Even though there are two other sections in the place, the user will always enter only one of those sections. In our application we have decided to use that section for anonymous users. Once our bidder gets information about the current section it turns out that it is the wrong section, so our bidder moves to the bidder section. The bidder can see who else is in the same section by using a user interface component called a place awareness list that shows all people in a specific section. The bidder gets information about the current auction item by listening to the place. This way information about place attribute values is sent to the bidder.

108

Working with the Sametime Client Toolkits

6.3.3 Entering as on-looker


Entering as an on-looker follows the same pattern as a bidder except that the on-looker stays in the section that was entered initially. The on-looker can also see who else is in the same section by using a place awareness list. Information about the current auction item is also passed on in the same way as for the bidder.

6.3.4 Bidding on an item


The user interface is different for bidders and on-lookers and it determines whether you can bid on an item. A bidder and an on-looker can see a picture and a description of the item as well as the current bid. They can also see the status (INACTIVE, ACTIVE, ONE, TWO, SOLD). In addition to this, the bidder can place a bid by writing the bid amount and pressing a bid button. The bid is sent as a data message to the auctioneer. The auctioneer receives the message with the bid amount and determines who the sender is. The auctioneer checks that the bid is a valid bid (for example higher than the current bid) and then relays the new bid to all participants by sending a message to all place members. The place attribute for the current bid amount is also updated by the auctioneer. In case the auctioneer has started to call the auction, the status is also reset to ACTIVE. If the bid is not valid the auctioneer will reply directly back to the bidder and not go any further.

6.3.5 Calling
The auctioneer has three buttons, with the labels One, Two, and Sold. When it is time to call the auction, the auctioneer clicks button One. This results in the auction status attribute of the place being set to ONE and a message about this calling being sent to all place members. As we saw in the previous section, a new bid will reset the status of the auction to ACTIVE. If no further bids arrive, the auctioneer clicks button Two, and following that, the Sold button. The same changes and notifications as for the first call are performed in each case. When the auction status attribute for the place is set to SOLD, nobody can place additional bids. Keep these flows in mind as we move on and look at the implementation.

Chapter 6. A place-based auction example

109

6.4 Client applications


To give you an idea of our final result we give you a preview of the user interface in our application before looking at implementation classes. We decided to supply two different clients for our three groups of users:

Auctioneer client is the user interface and dashboard for the auctioneer. AuctionCustomer client allows customers to participate in auctions, or simply watch if they have entered anonymously.
We implemented these clients as Java applets embedded into simple, static .HTML pages. However, you can as easily embed them into a JavaServer page (JSP) or another dynamic environment. In our design we strived for the sample to be flexible and extendable, so if you want, you can implement an HTML-only version for use with a PDA or a cellular phone that supports WML. For example, if using the Java client toolkit, the AuctionCustomer HTML client can be implemented by a servlet that handles the Sametime communication. See Figure 6-3 on page 111 for a functional diagram of the place that both of our clients access. You can see it maps very well to our analysis of the situation in Figure 6-2 on page 104.

110

Working with the Sametime Client Toolkits

Auction House Place

Place attributes

Current Item

Current Bid

Auction Status

Auditorium section

Stage section

Change Bid Authenticated users (Bidders)

Anonymous section Auctioneer

Anonymous users (watch only)

Figure 6-3 Auction architecture

The arrows show how messages or attribute modifications are happening. This figure does not show the listeners; they are described in detail later.

6.4.1 The auctioneers application at a glance


The auctioneer logs into Sametime using this simple login dialog:

Then the auctioneer enters an application, as shown in Figure 6-4 on page 112.

Chapter 6. A place-based auction example

111

Figure 6-4 The auctioneers application

We can group the user interface into these components: In the top left corner is the auction status area the current item, its details and the current mode of the auction. Below the status area are the auction controls: two buttons, labeled Start and One. The label on the Start button can be changed to Stop, and button One (first call) can be changed Two (second call) and Sold. In the top right corner are 2 place awareness lists for two sections, used for monitoring the users in the associated sections. At the bottom is a transcript area with a text entry field and a Send button When the auctioneer wants to start the auction, he presses the Start button and the auction is running. Now the customers can start bidding, while the auctioneer can send messages to all users (using the text field) or to individual users by clicking their names in the awareness lists. While the auction runs, the auctioneer also can start to complete the auction by clicking on the button labeled One. He also can always stop the auction by pressing the Stop button for any important reason. In case no new bids arrive, the auctioneer presses the Sold button and the item is sold to the user who entered the last bid. The auctioneer can move on to the next item.

112

Working with the Sametime Client Toolkits

6.4.2 The customers application at a glance


When the customer launches his application, a different login dialog opens:

If the user enters a name and clicks Anonymous, he will be logged in as an anonymous user, enter the anonymous section, be able to watch the auction only, and can log in at any desired point in time. If the user enters a user name and a valid password, he will log into Sametime as a normal user, enter the auditorium, and be able to participate in the auction. The customer application is shown in Figure 6-5.

Figure 6-5 The customers application

As you see, its layout is similar to the auctioneers. The main differences are: The auction controls are replaced by bidding controls. The availability of the Logout button, which can switch Login.

Chapter 6. A place-based auction example

113

The customer has only one place awareness list, showing him the users in the his section. The customer cannot send messages to all users at once, like the auctioneer can. If the customer entered as an anonymous user, he can click the Logout button, then log in again, with name and password, to participate as a normal customer.

6.5 The implementation


We now describe the implementation, but before looking at the individual classes we describe which Sametime services we used in our application. We show you a class diagram and briefly describe all classes in the application and their relationships, and give you some tips on how you can look at the full source code for this sample application.

6.5.1 Sametime services used


We use a select subset of the Sametime Java client toolkit in our application; we briefly describe the services we used in this section.

Core package
The core package (or parts of it) is always a prerequisite for doing any Sametime programming. We use the following parts:

Core types
This includes classes like STUser, STUserInstance, and STAttribute. See 2.5, Core types on page 42 for more information about core types.

Constants
The core constants contain declarations of constants we use for the level of encryption for the place, and error codes. The package also contains constants used for instant messaging and meetings.

Comparch
The Comparch package defines the core classes STSession, STEvent, and SessionTable, as well as the abstract interface STCompApi that virtually all services in the toolkit extends.

114

Working with the Sametime Client Toolkits

Community service
The community package is the next prerequisite for doing anything in Sametime. Its main class is STBase, which implements the community service. We use the community service to log into the Sametime community by password, by token, or anonymously.

Places service
The places package is the one we utilize most on our application. It contains the necessary classes and interfaces for the places architecture, as described in Chapter 3, Places architecture on page 49.

Awarenessui placelist service


Finally, we also use the Awarenessui place list package. This package is not required for the auction to work, but provides the lists so the bidders and on-lookers can see who else is in their section in the auction place. As a value add, this component not only lets the user see who else is in the same section, it also allows the user to start a chat with any of the listed users.

6.5.2 Class diagram


A class diagram showing all classes of the sample application is in Figure 6-6 on page 116.

Chapter 6. A place-based auction example

115

Figure 6-6 The auction house classes inheritance

Even though we have two applications, we only show one hierarchy because the Auctioneer and the AuctionCustomer share many classes. The classes used by only one of the applications are: Auctioneer AuctionItem AuctionManagerPanel AuctionCustomer CustomerBidPanel CustomerLoginDialog We generated the hierarchy view in VisualAge for Java (by selecting the package for our application and choosing Selected -> Open To -> 1 Classes). This is why there are some small symbols in the figure. The small square after some of the classes that looks like a document means that we do not have the source for that class. The letter A after a class means that this is an abstract class. Finally, the running figure after a class means that class is executable.

116

Working with the Sametime Client Toolkits

We discuss some of the classes individually a little bit further on; here we explain which classes map to the real world objects we listed in 6.2, Objects in the application on page 106.

Mapping to real world objects


Through our use of the Sametime toolkit, we use the classes and interfaces supplied to create and work with: A Place Sections within the place You will thus not see any classes in our application for place and section as they are supplied by the Sametime toolkit. We also use a variety of listeners from the toolkit to know what is going on and react accordingly. More about this a little later. During our design process, it became obvious that the Auctioneer and the AuctionCustomer have much in common. Therefore, we chose to create a common abstract class for these two types of place members. This abstract class is named AuctionUser; defined as follows: AuctionUser This class is the one that contains the most logic in our application, but if you want to investigate it further you have to look at it in connection with at least one the following two classes that extends it: Auctioneer AuctionCustomer The auction item is implemented by the class: AuctionItem A Sametime place cannot have an object like AuctionItem as a property. Only more simple types can be properties of a place. Therefore, we let AuctionItem be a property of the Auctioneer. The Auctioneer, in turn, extracts information from the auction item and sets the following place properties to describe the current auction item: description, location of image file, and minimum price.

Event listeners and adapters


We must listen for a variety of Sametime events in our application. In some cases we have implemented the appropriate listener interface in the class that needs to handle the events we listen for. Examples of this are in AuctionUser: LoginListener We need to add a LoginListener to know whether we have logged successfully into the Sametime community.

Chapter 6. A place-based auction example

117

MyMsgListener We need to add a MyMsgListener to be able to receive messages from other users. We can receive either text or data messages. These listener interfaces only have a few messages defined, so we do not have to add a lot of methods to our classes to utilize them. Another example where we implement a listener interface directly in our class is in AuctionCustomer: MySectionListener We use this when we need to switch to the auditorium section for authenticated users. The MySectionListerner either sends a sectionChanged or a changeSectionFailed message. Other listener interfaces in the Sametime toolkit define many messages. In these cases it makes sense to move the handling of these messages out in a separate object. In our case, the following listener interfaces define a lot of messages: PlaceListener The PlaceListener itself defines 11 messages and inherits six additional messages. We use it to figure out whether our user entered the place successfully, get notification when attributes change, get a handle to the sections in the place, and so on. SectionListener The SectionListener only defines four messages, but also inherits another six messages. We use it to figure out which users already are in the different sections. A class that implements a listener interface must also have methods for all the messages the interface defines. This is required even though we only are interested in a few of the messages. Thus there is good reason to implement the listener methods in a separate class: so our main class does not get filled up with a lot of method stubs. To make the implementation of such listener objects easier, the Sametime toolkit supplies Adapter classes. They are classes that implement a Listener interface and contain stub methods for all messages defined by the interface. We can then subclass such an adapter class, and only implement the methods for the messages we want to handle. We have three such adapter subclasses in our application:

118

Working with the Sametime Client Toolkits

APPlaceAdapter The APPlaceAdapter extends the PlaceAdapter class, which implements the PlaceListener interface. We use APPlaceAdapters for listening to place events for our Auctioneer and AuctionCustomer clients. In our implementation we chose to handle six of the 17 messages defined. We do not do any fancy processing, but simply forward the event to our main class (Auctioneer or AuctionCustomer) that set up the adapter. APSectionAdapter This class extends the SectionAdapter, which implements the SectionListener interface. The only event we listen for is the usersEntered message. In this case we also simply forward the event to the class (Auctioneer or AuctionCustomer) that set up the adapter. APUIPlaceAdapter In our interim implementations we let the main class receive notification when place attributes changed and then passed that information on to the user interface classes. However, to have as little UI code as possible in our main classes, we decided to let the UI classes listen directly to the place instead of using the Auctioneer or AuctionCustomer classes as relays. We created APUIPlaceAdapter, which extends the PlaceAdapter, for this purpose. For the UI we only want to know when attributes in the place change, so the only message we have implemented a method for in the adapter is attributeChanged.

User interface classes


We do not a have a totally clean separation of model and user interface. There is a little bit of UI (like the transcript panel) in our main classes. In addition, we have the following UI classes. APPanel This is an abstract class that extends Panel and is inherited by some of our UI classes. We introduced it to use as the core class for our APUIPlaceAdapter. Thus APPanel contains a method stub for the attributeChanged method. The Auctioneer class implements an entry field, a send button and a transcript area itself. In addition, it uses the UI classes that you can see in Figure 6-7 on page 120.

Chapter 6. A place-based auction example

119

Auctioneer

AuctionStatusPanel m_auctionStatusPanel PlaceAwarenessList m_anonymousAwarenessLIst AuctionManagerPanel m_auctionManagerPanel PlaceAwarenessList m_AuditoriumAwarenessList

TextArea m_taTranscript

TextField m_tfSend

Button m_btnSend

Figure 6-7 Auctioneer user interface classes relationship

Starting in the middle left side and moving clock-wise around the diagram, the classes are described as follows: AuctionManagerPanel This panel extends APPanel and implements the Start/Stop and the Call (One, Two, Sold) buttons. It uses APUIPlaceAdapter to listen for changes in the status of the auction and updates the labels of the Start/Stop and the Call buttons accordingly. This class also initializes the following class: AuctionStatusPanel AuctionStatusPanel class extends APPanel and is responsible for displaying information about the current auction item, as well as the auction status (active/inactive). It uses APUIPlaceAdapter to listen for changes in the auction item attributes, like latest bid. PlaceAwarenessList This class is part of the Sametime Java toolkit. It displays all users in a specific section in a place. Thus the Auctioneer uses two lists to be able to see all bidders (in the auditorium section) and all on-lookers (in the anonymous section).

120

Working with the Sametime Client Toolkits

As you see in Figure 6-8, the UI of the AuctionCustomer is very similar to that of the Auctioneer.

AuctionCustomer

AuctionStatusPanel m_auctionStatusPanel PlaceAwarenessList m_mySectionAwarenessLIst

CustomerBidPanel m_pnlBidPanel

TextArea m_taTranscript

Figure 6-8 AuctionCustomer user interface classes relationship

Only one PlaceAwarenessList is used (so users only can see those in the same section as they are in). The other difference is that the AuctionManagerPanel is replace by: CustomerBidPanel This panel extends APPanel. It is responsible for supplying the entry field and Bid button so the user can place a bid. These controls are disabled if the user is anonymous. The panel also supplies a Logout/Login button to allow anonymous users to log out and then log in again as an authenticated user that can bid on the auction items. It uses the APUIPlaceAdapter to listen for the auction status attribute. If the status is INACTIVE or SOLD, the bidding controls are disabled. All other status messages will result in the controls being enabled. The remaining UI classes are simple helper objects: ImageCanvas This class is a simple Canvas, which shows any picture. It is used to display the picture of the current auction item, whose location is passed along to us as a place attribute.

Chapter 6. A place-based auction example

121

LoginDialog and CustomerLoginDialog These are simple dialogs for authentication. The CustomerLoginDialog allows the user to select authenticated login or anonymous entry.

6.5.3 Looking at the code


If you want to browse through the auction house classes, you can use the JavaDoc supplied as additional Web material for this book. See Appendix E, Additional Web material on page 407 for instructions on how to get the material. The JavaDoc files contain the important comments, and link together the classes, interfaces, and methods. Similar to JavaDoc, we also provide the complete source in HTML format generated using a tool called Java2HTML. The usage is similar to JavaDoc, but youll have the Java source with Syntax highlighting. In addition, an integrated development environment, like VisualAge for Java, helps to browse through classes and methods that we supply in a jar file, and to make modifications to our samples easily so that you can quickly start experimenting.

6.5.4 Launching and passing parameters to the applets


While we focus on the Java code in implementing the place sample, you may wonder how we get the applets launched. In this section we briefly introduce the .HTML files launching both types of applets. In the real world the list of auction items will be supplied from a relational database, an XML stream returned by a Web service, or some similar function. However, for this sample we simply provide the list of auction items as parameters to the Auctioneer applet. In Example 6-1 on page 123 you see the HTML for the Auctioneer applet. It provides the auction item list the following way: The parameter numItems represents the number of items. Each item follows, with three more parameters for title, picture URL and minimum price. Note the last parameter DefaultImageURL, which provides the picture shown when there is no auction item. You can supply additional parameters to automate the login. See the login() method of the Auctioneer class.

122

Working with the Sametime Client Toolkits

Example 6-1 HTML for Auctioneer applet


<HTML> <HEAD> <TITLE>Auctioneer</TITLE> </HEAD> <BODY BGCOLOR="C0C0C0"> <APPLET CODE=com.ibm.redbooks.sg24_6666.Auctioneer.class WIDTH=100% HEIGHT=100%> <param name=archive value="6666auction.jar,CommRes.jar,STComm.jar"> <param name=DefaultImageURL value="default.jpg"> <param name=numItems value=2> <param name=Item1Title value="Arizona Sun"> <param name=Item1URL value="AZSunc.jpg"> <param name=Item1Price value=1000> <param name=Item2Title value="Linux Watch"> <param name=Item2URL value="watchlg.jpg"> <param name=Item2Price value=500> </APPLET> </BODY> </HTML>

The .HTML file for the AuctionCustomer is even simpler: see Example 6-2. The DefaultImageURL is used here also, to show an image until the place attribute is received.
Example 6-2 HTML for AuctionCustomer applet
<HTML> <HEAD> <TITLE>AuctionCustomer</TITLE> </HEAD> <BODY BGCOLOR="C0C0C0"> <APPLET CODE=com.ibm.redbooks.sg24_6666.AuctionCustomer.class WIDTH=100% HEIGHT=100%> <param name=archive value="6666auction.jar,CommRes.jar,STComm.jar"> <param name=DefaultImageURL value="default.jpg"> </APPLET> </BODY> </HTML>

In Appendix B, Working with the auction house sample material on page 375, we describe how to install our sample if you want to try it out yourself. We now move on to look at the dynamics in our application.

Chapter 6. A place-based auction example

123

6.6 Event flows


In this section we explain the flow of events in our application and describe the design of possible interactions. The discussion is grouped into three phases and is described for each application: Startup Auction Shutdown In this phase we describe how the applications initialize and prepare for the auction. There is no interaction yet. This phase is about the direct interaction of Auctioneer and AuctionCustomers. The final phase for leaving the auction and clean up. This phase also has no interaction.

In Table 6-1 you see the event flow for the startup phase, while both the Auctioneer and all the AuctionCustomers prepare for the auction. There is no interaction yet.
Table 6-1 Startup phase
Event init() Description Called when the applet was loaded in the browser. Called when the browser wants the applet to start. Called by the Community Service if the login was successful. Called by the Places Service if the place was entered successfully. Auctioneer actions Read the item information from applet parameters. Initialize the UI. Try to login. Create the place object, Create the place adapter, Register for place events, Try to enter the place Listen to the stage section. Listen for MySelf events. Initialize auction status. Activate first item. Limit access to stage. Enable UI. Listen to my section. Listen for MySelf events. Bind the PlaceAwarenessList. Enable UI. AuctionCustomer actions Initialize the UI.

start() loggedIn()

entered()

attributeChanged()

Called by the place initially after entering the place for each relevant attribute.

The UI components for the clients reflects the relevant changes.

124

Working with the Sametime Client Toolkits

Event sectionAdded()

Description Called by the place Service after entering the place for each section in the place.

Auctioneer actions Listen to this section. Identify stage, anon and auditorium section. Bind awareness lists to section. -/-

AuctionCustomer actions Listen to this section. Identify stage, anon and auditorium section. If login was not anonymous try to change section. Listen to the new section. Bind place awareness list to new section.

sectionChanged()

Called by the place when the section was changed.

userEntered()

Called initially for each user in the place/section.

Check if user is on stage, remember as the auctioneer.

Now, when both actors have entered the auction place, the interactions begin. Since the auctioneer controls the session, the customer cannot do anything until the auction is started. A typical auction runs as follows: The auctioneer changes the auction status to active by changing a place attribute. The customers start bidding by sending data to the auctioneer. The auctioneer automatically accepts/rejects the bids. The auctioneer calls 1-2-Sold, again by changing the place attribute. The auctioneer stops the auction. See Table 6-2 for a general description of the used events.
Table 6-2 Auction phase
Event textReceived() Description Another place member has sent text. Auctioneer actions AuctionCustomer actions

Add to the transcript area. Note: In our sample only the Auctioneer UI has the ability to send text messages.

Chapter 6. A place-based auction example

125

Event dataReceived()

Description A customer sent a bid.

Auctioneer actions Check the bid is sent by an authenticated user from the auditorium section. Compare the bid to the current bid, either accept the bid and notify sender and all users, or reject the bid and inform sender only.

AuctionCustomer actions -/-

attributeChanged()

Called by the place when an attribute (for example the bid attribute) has been updated.

The UI components reflects the change.

The shutdown phase is entered when a user closes his window. If an AuctionCustomer logs out or logs in while the auction is performed, the application runs through parts of the shutdown phase (leave()), followed by parts of the startup phase. See Table 6-3 for a description of the related events.
Table 6-3 Shutdown phase
Event stop() left() Description Called when applet is stopped. Called when we left the place. Auctioneer actions AuctionCustomer actions

Close the login dialog if needed, remove the UI, leave the place. Remove listener on section and place. Close the place. Log out. If the reason was a wrong password then try to log in again. Remove listener on section and place. Log out. -/-

loggedOut()

Called when logout() was processed or for other reasons. Called when the applet has to free all resources.

destroy()

Stop and unload the session.

If you want to get an idea of how some of this flow looks in our final sample, look at Appendix C, Sample auction scenario on page 381. There we take you through an auction scenario and show screens for each step.

126

Working with the Sametime Client Toolkits

6.7 Leveraging the places architecture


When implementing the auction house, we were trying to leverage the places architecture as much as possible. In this section we describe some of the features we used. The places service gives us access to an auction place with all the features in the place, like sections, attributes, and activities. We use the sections to: Separate users from each other to easily list them in place awareness lists Protect the stage by assigning an access control list To broadcast messages to all users in the place, the Auctioneer sends messages to the place object, which automatically forwards them it to all place members, saving us a lot of work and list maintenance. This is one of the privileges a user in the stage section has. Users in other sections cannot broadcast messages in this manner. We use attributes to describe the current status of the auction, not messages. It is important to understand the difference: a message can only be received when you are in the place in the moment the message is sent; the attribute will be sent by Sametime automatically when the user enters the place. We do not use activities in the sample, because the Sametime Java client toolkit has no way to create (new) activities. One could imagine having an activity to handle some of the housekeeping, instead of requiring an Auctioneer user to be logged in all the time. In the redbook Working with the Sametime Community Server Toolkit, SG24-6667 we show how to add an activity to this sample..
Clarification: You can add Sametime standard activities, for instance the white board, easily using the Sametime 2.5 toolkit. You just cannot implement new activities without using the server toolkit.

We now discuss how you can leverage the places architecture in your own applications. In the following sections youll learn about the functions and restrictions the places architecture offers you. We describe possible actions (for instance, sending text messages), depending on the environment (sender, receiver, location). As a sender we only describe the users view, since this is the only object you can program with the client toolkit.

Chapter 6. A place-based auction example

127

Note: We look at the server-side capabilities in places in the companion redbook Working with the Sametime Community Server Toolkit, SG24-6667.

The receiver can be any place member (user, section, activity, place). The location is the section your user has entered. Sametime distinguishes between the stage section and the other sections. In applications developed with the 2.5 Toolkit there are always one stage section and two other sections. We also give some ideas on where to use the described features, and finally, how we used it in the auction house sample.

6.7.1 Sending text and data


As a place member, you can send text and data to other place members: users, sections, activities, and the place itself. You have to get hold of the receiver object at the right time to be able to use this. Typically there are two ways to get in touch with place member objects: 1. You receive PlaceMember objects when the place or the section sends you events about place members entering/leaving the place or section. 2. Other place members send you messages directly. Table 6-4 shows your options for sending messages to individual users, sections, the whole place, or activities, depending on whether you are in the stage section or in one of the other sections.
Table 6-4 User sending text and data to place members
Receiver User Section Place Activity Sender on stage Allowed (to any user) Allowed (to any section) Allowed Allowed (to any added activity) Sender off stage Allowed (to any user) Allowed to own Not allowed Allowed (to any added activity)

section only

As you can see in the table, the user on stage has more options to send text and data to other place members. For instance, by allowing only some users on the stage, you can ensure that place messages are always coming from a trusted user.

128

Working with the Sametime Client Toolkits

In the auction house sample we allow only the auctioneer on the stage (by having the auctioneer user set an access list for the stage that only contains the user itself), and when the auctioneer notifies all users the messages are sent to the place. No other client can send messages to the place (and disturb the bidding) because they cannot enter the stage section.

6.7.2 Changing attributes


Another way to notify place members is to change attributes. There are the following main differences between sending text or data messages: Messages are sent to the receiver, while attributes stay associated with Sametime objects. For instance, if a message was sent to the place, the place object accepts the message, forwards it to all place members currently in the place, and forgets about the message. On the other hand, a place attribute would be notified with its current content to any user entering the place, and if the attribute is changed, all users in the place are notified. Attributes can be heavy, and Sametime has some specialized handling options. For more details see 2.5.4, Sametime attribute types on page 46. Table 6-5 shows which attributes a user is allowed to change, depending on whether that user is in the stage section or one of the other sections.
Table 6-5 User changing attributes
Object associated with attribute User Section Place Activity User on stage May change own attributes only. May change own sections attributes only. Allowed. Not allowed. User off stage May change own attributes only. May change own sections attribute only. Not allowed. Not allowed.

As you can see in the table, users can change their own attributes and their sections attributes. Users on the stage can change place attributes, while other users cant. Again, you can use these limitations to establish some trust in your application. Since the stage access can be limited, a place attribute can be trusted more than a section attribute. Another view could be that users notify other users in the same section about status changes using attributes.

Chapter 6. A place-based auction example

129

In the auction house sample we use places attributes set by the auctioneer to reflect the status of the auction.

6.7.3 Receiving events


In the preceding sections we discussed how information can be distributed in a Sametime place. Now we need to understand which events we may, and may not, receive. Sametime uses the following mechanisms to provide relevant events:
Manual subscriptions

For most events, your application has to register an object as a listener. For instance, if you want to listen to place events, you need to register an object implementing the PlaceListener interface. Subscribing does not mean that all possible events are forwarded: Sametime does some filtering. For instance, if your application listens to place events, the entered() method is called only if your applications object successfully entered the place. It will not be called when other users enter the place.
Automatic subscription changes

The mySelfListener() interface methods are called with relevant messages automatically. So your application has to subscribe for MyselfEvents only once, and all relevant events are sent using the dataReceived() or textReceived() methods. For instance, if another section is entered, automatically all messages sent to the new section are forwarded using these methods, while the previous sections messages are not arriving any more. We also want to note here that the object sending events also receives this event. In case of an error, only the sender will receive a failure event instead. Table 6-6 on page 131 gives an overview of under which circumstances a user in a place receives a message, or how to get notification about a changed attribute, a place/section entered, or activity added/removed event.

130

Working with the Sametime Client Toolkits

Table 6-6 Sametime subscription rules


Action or event Send Text/Data Directed to User Section Place Activity Change Attribute User Section Place Activity Place entered/left Section entered/left User object Receives only if directed to this user object. Receives only if this user object is member of the section. All users receive. The sending user object receives failure notification if the message to the activity failed. May subscribe to any other users attribute changes. May subscribe to any sections attribute changes. May subscribe to place attribute changes. May subscribe to any activitys attribute changes. Only for this users object. Received only for other users in this section, while users in other sections still can subscribe and then receive this event. Received by any user.

Activity added/removed

In the auction house sample application we register only the needed listeners, and receive only the messages we need to perform the auction. If you look at the code, you may wonder why the method attributeChanged in the AuctionCustomer class does not do anything. How does the bidder know when a new bid has arrived? The explanation is that the user interface class (named AuctionStatusPanel) for the bidder also has registered a listener (named APUIPlaceAdapter) with the place. Thus the view gets the required data to display directly from the source. The bidder sees the higher bid, and can then manually place a higher bid. Consider that a bidder might want to bid automatically on an item up to a certain amount. In this case it makes sense to handle this in the AuctionCustomer class. We have added sample code in the additional Web material to illustrate a very basic example of such auto bidding. To try it out you just need to remove two lines that are commented out in the constructor method or the CustomerBidPanel class. This will add an extra button in addition to the Bid and Logoff buttons. Once the user presses this button, the application will automatically place a bid

Chapter 6. A place-based auction example

131

that is 100 higher than what other bidders place until it reaches an amount of 10000. Note that this is just a simple illustration using hard-coded values with no exception handling. For example, if several users are using automatic bidding you may have racing conditions where the same amount is being bid almost simultaneously. The first bid will be accepted while the others will be rejected as being too low. Our sample does not handle this; it does not place a higher bid after having one rejected as being too low, but it can be extended to handle this. We leave this to you as an exercise. Currently the bid rejected message is sent as text from the Auctioneer. You may want to change that to a data message and act on it in your code beyond simply writing the message to the transcript window.

6.7.4 Organizing messages, events, attributes


When designing a Sametime application, the many features of the places architecture may be hard to grasp. It may not be easy to structure your application the right way. This is why we provide and explain the auction house sample application. To help you avoiding pitfalls, we try to discuss some common ones in Table 6-7.
Table 6-7 Common pitfalls and how to avoid them
Problem description Solution You can send messages only to your own section, so this message is filtered. You have two solutions here: Enter the stage first, or send the message to the users in the stage section directly. You can only modify your own sections attributes, so you need to enter the section first, or you have to use a place attribute.

I cant send messages to the stage section! To notify users in the stage section, I try to send messages to the section PlaceMember object. I cant set attributes of other sections, even if Im on the stage! I want to set a sections attribute, but it does not work. My user object is on the stage. I do not receive messages sent to a section! I want to listen to messages sent to a section, but it does not work, even when I subscribe to the section

Subscribing to the section event only gives you the SectionListener events (primarily that users enter/leave a section), but not the messages. To listen to the messages, you have to enter the section and you will receive them through the MyMsgListener interface.

132

Working with the Sametime Client Toolkits

6.7.5 Other considerations


As you read through this chapter and look at the code, there are plenty of topics to consider. Here we mention a few of the other considerations we had when doing this sample.

How to know the place name


Our sample does not scale very well because the place name is hard coded (to AuctionHouse). To be able to use our applications to enter different auctions, the place name must be passed as a parameter to the application. There are several options for doing this: Passing the place name as a parameter in the HTML file that launches the AuctionCustomer applet. If the AuctionCustomer applets are launched from a server you control, this approach is relatively easy to handle. Entering a place that acts as a lobby and reads the names of the current auctions from the attributes in that place. This approach is more flexible and scalable. You can easily change the place name and add additional places. If your places are password protected, you can add an access list to the stage section in your lobby-place and make the place passwords available as attributes of the stage section. This way you make sure that only those in your access list can get the password for other places and thus enter them. You still need to transfer the name of the lobby-place by some means, but since this place will be relatively long-lived, passing as a parameter in an HTML file is OK. If you utilize the approach of passing information via the stage section that is protected by an access list, little harm is done if the name of the lobby-place is revealed to others.

How to throw a user out of a place


We pondered what to do if a user suddenly behaves irresponsibly. For example, a user bids on everything without having the funds to go through with the payment. We havent found any way to throw a user out of a place using the functionality in the client toolkits. The approach to use is to control who you let into the place. If you have a user in a place that you do not want there, you can shut the place down and create another where this user cannot enter. This can be done by simply removing the offending user from the directory that Sametime authenticates against, or, as discussed above, password protecting the place and making sure the password is kept secret from the offending user.

Chapter 6. A place-based auction example

133

How to make a bid from a cell phone


In todays wireless world it is desirable to offer bidders the ability to bid from cell phones. We can offer a cell phone WAP client using Sametime client toolkit capability. We need a proxy object that communicates with the Sametime server and translates the data to WAP, which the cell phone can handle. We can use a servlet as such a proxy object. However, the Sametime Community Server Toolkit offers far better capabilities for supporting alternative clients in a scalable manner. On the server side we can create a Mux server application that, among other things, allows several users to log into Sametime while sharing a single connection to the server. Refer to the redbook Working with the Sametime Community Server Toolkit, SG24-6667 to learn more about the capabilities for server-side programming. Another question is whether and how to integrate such a solution with the Sametime Everyplace product, which gives you access to awareness and chat on a WAP enabled cell phone. We would like to avoid prompting the user to authenticate twice. However, we did not get around to looking into this topic.

6.8 What is next


We developed the auction house sample to explore the possibilities and considerations for Sametime places. We urge you to download the source of our sample from the IBM Redbooks Web site and experiment with it. See Appendix E, Additional Web material on page 407 for instructions on how to get the code. In Appendix B, Working with the auction house sample material on page 375 we also describe how to give the executable code a run. When you go through the code, remember that it is not production code. We have not subjected it to rigorous testing, and there may very well be a few bugs here and there. However, you still get a working, complex sample that can help you grasp the concept and possibilities of Sametime places quickly. If you want to see more examples of places in use, see Chapter 9, A complex meetings sample on page 207, where a place is set up to host a meeting. With the redbook Working with the Sametime Community Server Toolkit, SG24-6667, we provide an expanded version of this auction house sample for your further exploration. Among the things we add is a server-side activity to handle some of the auction management.

134

Working with the Sametime Client Toolkits

6.9 Summary
In this chapter we have taken a stab at solving a real-world problem with our auction house sample. We have taken you through the traditional auction we modeled our solution after. Requirements like being able to communicate in real time, different rights for different groups of people, independence of physical location, and so on, fit very well with the Sametime Place architecture. We described the main classes we created based on the real-world objects and we looked at the flow in the application. We described the implementation further and finally we discussed some of the experiences and considerations we had during our work with the auction house sample. This includes tables that list what you can and cannot do in a place depending on which section you are in and where you are directing your action.

Chapter 6. A place-based auction example

135

136

Working with the Sametime Client Toolkits

Chapter 7.

Customized chat UI applet


In this chapter we work on some other samples that use the Sametime Java client toolkit. While we did not focus very much on the UI applets provided with the Sametime Java Toolkit in the previous chapter, we take a very detailed look at the CustomizeChatUI applet here. It is new with the Sametime 3.0 Java client toolkit. In this chapter we make our own version of the CustomizeChatUI applet and discuss how it can be deployed. We show an example of how it can be deployed in a Lotus Domino database. Then we extend our CustomizeChatUI sample further, and utilize the Sametime storage service to keep canned messages that users can attach to a button in the chat applet. Finally, we show an example of how we can launch a second Sametime applet in our browser and log into Sametime by utilizing the Sametime Token service. When we pass a token to the new applet, the user does not have to authenticate a second time.

Copyright IBM Corp. 2002. All rights reserved.

137

7.1 Customized ChatUI Example 2


In the example in Chapter 6, A place-based auction example on page 101 our client application has a UI list where the user can see who else is in the same section and initiate a chat with any of those users by right-clicking on their name and selecting chat on the pop-up menu. A chat window will then open and the users can type in their chats. In the Sametime 2.0 Java toolkit there was no way to change the look of the chat window, but Sametime 2.5 added the ability to customize parts of the window. An example illustrating how to do this is included with the Sametime 3.0 Java toolkit. Read the section titled Customizing the Chat UI Component in the Sametime 3.0 Java Toolkit Developers Guide that is provided with the toolkit as a PDF file to learn more about the toolkit sample. In this chapter we take that toolkit sample and customize it further. To avoid confusion with the original sample we have added the number 2 to our class names.The example code provides the details of adding custom buttons and other user interface (AWT) components to a chat-based applet. The basic chat user interface provided by Sametime is good, but the user experience may be enhanced by providing additional functionality. This functionality may be a button to send a custom message, or the ability to add our own tag line to each message we post. As previously stated, adding new functionality to the user interface enhances their experience. The more the user enjoys using an application, the more they will use it. No matter how great an application is perceived to be, it must be used and accepted by the user community to be ultimately successful. On the flip side, adding new functionality may cause confusion. Additionally, this new functionality may present requests to enhance other areas where chat is utilized. Every area of enhancement will present positive and negative attributes, but the ultimate result rests on the shoulders of the user community. The following example customizes the ChatUI interface, as you can see in Figure 7-2 on page 139. The example adds buttons, check boxes, a text field, and numerous menu items for user selection. Figure 7-1 on page 139 shows the basic launchpad we use in the example to open our chat window.

138

Working with the Sametime Client Toolkits

Figure 7-1 CustomizeChatUI2 applet

Figure 7-2 CustomizeChatUI2 chat dialog

The example contains an applet that logs into the Sametime community and allows the user to initiate (and receive) instant messages via a Sametime chat session. The applet provides a field to enter meeting invitee names (one or more), a check box to select whether the Invite dialog window is displayed, and a

Chapter 7. Customized chat UI applet

139

button to initiate the chat. Additional buttons are provided in the actual chat window for sending custom messages, logo graphics are included in the top of the chat window, a text field is included to add a custom signature or tag line, and a custom menu with clickable URLs is added to the chat window.

7.2 Important classes in the sample


The example contains three classes: CustomizeChatFactory2 CustomizeChatUI2 ImagePanel We now describe each of these classes.

7.3 CustomizeChatFactory
The CustomizeChatFactory class responds to calls from the CustomizeChatUI components by generating the appropriate component for the request. This class extends the DefaultChatFactory class; it allows a custom user interface to be created/presented.

7.3.1 Methods
The following methods are found in CustomizeChatFactory: CustomizeChatFactory - Constructor Accepts Sametime Session and Applet objects representing the working environment. The Session object is passed to the parent constructor (DefaultChatFactory class). A local Applet object is set to the passed object for reuse. TextSubmitted - Method inherited from TextModifier Interface (implement). This allows chat text to be modified. It intercepts text submitted; the method accepts the text and modifies it accordingly before sending it to the chat area. getTextModifier - Returns TextModifier object from the ChatFrame object passed into it. This is required to provide the ability to manipulate the submitted chat text by way of the TextSubmitted method. getCustomizedPanels - Allows custom panels to be added to the Chat component window. A maximum of three panels can be added either to the top, bottom, or center using constants from the DefaultChatFactory class. The method accepts two parameters:

140

Working with the Sametime Client Toolkits

panelPosition - Integer (1-3) of the panel to be added The panelPostion parameter may be one of the following constants from the DefaultChatFactory class: TOP_PANEL top of user panel under menu CENTER_PANEL center of user panel above buttons BOTTOM_PANEL bottom of user panel above status bar

Frame - ChatFrame container for the panels getCustomizedMenu - Used to add a menu bar to the menu. The method accepts one parameter containing the MenuBar object to be manipulated. The default menu items (Meeting and Edit) may not be altered in any way. ShortcutButtons - Used to create the center panel, which includes customized buttons and a check box. getTimeStamp - Used to add a time stamp to the text presented in the chat window. createLogoPanel - Method used to create the panel containing a logo graphic. This method takes advantage of the ImagePanel class to work with the graphic. The method accepts one parameter, the graphic filename. getLogoURL - Method used to returnthe full URL of a logo graphic file. The code base property of the applet is used to calculate the full URL of the graphic. It accepts one parameter containing the logo filename. formatMessage - Method used to properly format chat window text according to user selections (checkboxes). The appropriate text is added to the text by way of user selections and data entered into the signature text field. We now walk through the full source code for the class.

7.3.2 CustomizeChatFactory2.java
The following pages contains the full source listing for the CustomizeChatFactory2 class. We have numbered important lines in the code and we explain those lines after each code element.

Imports and class declaration


import import import import import import import import java.awt.*; java.awt.event.*; java.util.*; java.applet.*; java.net.*; java.text.DateFormat; com.lotus.sametime.chatui.*; com.lotus.sametime.chatui.invitation.*;

Chapter 7. Customized chat UI applet

141

import import import import

com.lotus.sametime.core.constants.*; com.lotus.sametime.core.comparch.*; com.lotus.sametime.core.types.*; com.lotus.sametime.resourceloader.ResourceLoaderService;

1.public class CustomizeChatFactory2 extends DefaultChatFactory implements TextModifier { 2. Checkbox checkbox1, checkbox2, checkbox3; 3. final String checkbox1Label = "Add Time Stamp"; final String checkbox2Label = "Include Signature"; final String checkbox3Label = "Include Smiley"; 4. Label label1; 5. final String label1Text = "Signature: "; 6. TextField textfield1; 7. Panel buttonsPanel, signatureSubPanel, signaturePanel, checkboxPanel; 8. Button button1, button2, button3, button4; 9. final String button1Text = "Hey, wanna go to lunch?"; final String button2Text = "I am napping; let's talk later."; final String button3Text = "Boss is approaching, gotta get to work."; final String button4Text = "Time for a break; meet me in the breakroom."; 10. final String button1Label = "Go to lunch"; final String button2Label = "Taking nap"; final String button3Label = "Boss"; final String button4Label = "Break"; 11. final String logoFilename = "logo.gif"; 12. final String smiley = " :) "; 13. final String beginSignature = " [- "; final String endSignature = " -]"; 14. final String urlText1 = "http://www.lotus.com/"; final String urlText2 = "http://www.sametime.com/"; final String urlText3 = "http://www.ibm.com/"; final String urlText4 = "http://www.ibm.com/redbooks/"; final String urlText5 = "http://java.sun.com/"; 15. final String menuLabel1 = "Favorites"; 16. final String menuitemLabel1 = "Lotus"; final String menuitemLabel2 = "Sametime"; final String menuitemLabel3 = "IBM"; final String menuitemLabel4 = "IBM Redbooks"; final String menuitemLabel5 = "Sun Java"; 17. Applet m_applet; 18. Date m_date = new Date();

Explanation of numbered lines: 1. CustomizeChatFactory2 class is declared. It uses the DefaultChatFactory as its base and implements TextModifier to handle working with chat text.

142

Working with the Sametime Client Toolkits

2. Java AWT Checkbox objects are created for use on the Chat window. 3. The text associated with the Label objects is set up. This makes it easy to alter the text. 4. Java AWT Label object is created for use in the Chat window. It will be associated with the signature text field. 5. The text for the Label object is set up. 6. Java AWT TextField object is created for use in the chat window. This is used for user entry of signature value. 7. Java AWT Panel objects are created for setting up the chat window interface. 8. Java AWT Button objects are created for use in the chat window. These will be used to send predetermined chat messages. 9. Chat text associated with Button objects is created. This allows the text to be easily altered in one location. 10.Label text for the buttons is created for presentation in the chat window. 11.The filename for the logo used in the chat window is created. 12.String object used to format the text displayed for the smiley checkbox. 13.String object used to format signature text entered by user and displayed in window if appropriate check box is selected. 14.The URLs associated with menu item selections are created. 15.The label for menu added to chat window is created. 16.The text labels for menu items associated with new menu are created. 17.A Java AWT Applet object is used to work with current applet. 18.A Date object is used to add a timestamp to chat text.

Constructor method
19. public CustomizeChatFactory2(STSession session,Applet applet) super(session); m_applet = applet; } {

Explanation of numbered line: 19.The Constructor method calls the constructor of the parent class (DefaultChatFactory) and initializes the Applet object.

TextSubmitted
20. public String TextSubmitted(String text) String tempText = ""; {

Chapter 7. Customized chat UI applet

143

21. tempText = formatMessage(text); return tempText; }

Explanation of numbered lines: 20.The TextSubmitted method is used to intercept and manipulate chat text before it is posted in the chat window. 21.The formatMessage method is used to manipulate chat text.

getTextModifier
public TextModifier getTextModifier(ChatFrame frame) return this; } {

getCustomizedPanels
22. public Panel getCustomizedPanels(int panelPosition, ChatFrame frame) 23. if (panelPosition == TOP_PANEL) return createLogoPanel(logoFilename); 24. if (panelPosition == CENTER_PANEL) return ShortcutButtons(frame); return null; } {

Explanation of numbered lines: 22.Custom Java AWT Panels are added to the chat window. Sametime allows the addition of three custom panels. 23.A logo panel is added to the top of the chat window. 24.A panel containing buttons, check boxes, and a textfield is added to chat window.

getCustomizedMenu
25. public void getCustomizedMenu(MenuBar mb) { 26. Menu menu1 = new Menu(menuLabel1); 27. MenuItem menuItem1 = new MenuItem(menuLabel1); 28. menuItem1.addActionListener(new ActionListener() { 29. public void actionPerformed(ActionEvent event) { try { 30. m_applet.getAppletContext().showDocument(new URL (urlText1),"target"); } catch (MalformedURLException e) {

144

Working with the Sametime Client Toolkits

e.printStackTrace(); } } }); 31. MenuItem menuItem2 = new MenuItem(menuitemLabel2); menuItem2.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { try { m_applet.getAppletContext().showDocument(new (urlText2),"target"); } catch (MalformedURLException e) { e.printStackTrace(); } } }); 32. MenuItem menuItem3 = new MenuItem(menuitemLabel3); menuItem3.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { try { m_applet.getAppletContext().showDocument(new (urlText3),"target"); }catch (MalformedURLException e) { e.printStackTrace(); } } }); 33. MenuItem menuItem4 = new MenuItem(menuitemLabel4); menuItem4.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { try { m_applet.getAppletContext().showDocument(new (urlText4),"target"); }catch (MalformedURLException e) { e.printStackTrace(); } } }); 34. MenuItem menuItem5 = new MenuItem(menuitemLabel5); menuItem5.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { try { m_applet.getAppletContext().showDocument(new (urlText5),"target"); }catch (MalformedURLException e) { e.printStackTrace(); } } }); 35. menu1.add(menuItem1);

URL

URL

URL

URL

Chapter 7. Customized chat UI applet

145

menu1.add(menuItem2); menu1.add(menuItem3); menu1.add(menuItem4); menu1.add(menuItem5); 36. mb.add(menu1); }

Explanation of numbered lines: 25.Custom menus are added to the chat window. 26.New menu drop-down is created for the chat window. The previously declared text label is used for the menu label. 27.New menu item is created to be added to the custom menu. The previously declared text label is used for the item. 28.ActionListener is added to the new menu item to handle its selection accordingly. 29.The selection of the menu item is handled. 30.Specific URL is opened in a new window from chat window upon selection of the menu item. The previously defined URL address is used. 31.Second menu item is added to the menu and selection is handled. 32.Third menu item is added to the menu and selection is handled. 33.Fourth menu item is added to the menu and selection is handled. 34.Fifth menu item is added to the menu and selection is handled. 35.Menu items are added to the new drop-down menu. 36.Menu is added to the chat window.

ShortcutButtons
37. private Panel ShortcutButtons(ChatFrame frame) { 38. final ChatFrame chatFrame = frame; 39. Panel centerPanel = new Panel(new BorderLayout(4,0)); 40. button1 = new Button(button1Label); 41. button1.addActionListener(new ActionListener() { 42. public void actionPerformed(ActionEvent event) { 43. chatFrame.getChatModel().sendMessage(formatMessage(button1Text)); } }); 44. button2 = new Button(button2Label); button2.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { chatFrame.getChatModel().sendMessage(formatMessage(button2Text)); } });

146

Working with the Sametime Client Toolkits

45. button3 = new Button(button3Label); button3.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { chatFrame.getChatModel().sendMessage(formatMessage(button3Text)); } }); 46. button4 = new Button(button4Label); button4.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { chatFrame.getChatModel().sendMessage(formatMessage(button4Text)); } }); 47. buttonsPanel =new Panel(new FlowLayout(FlowLayout.LEFT)); 48. buttonsPanel.add(button1); buttonsPanel.add(button2); buttonsPanel.add(button3); buttonsPanel.add(button4); 49. signatureSubPanel = new Panel(new FlowLayout()); 50. textfield1 = new TextField(60); 51. label1 = new Label(label1Text); 52. signatureSubPanel.add(label1); signatureSubPanel.add(textfield1); 53. signaturePanel = new Panel(new BorderLayout()); signaturePanel.add(signatureSubPanel, BorderLayout.EAST); 54. checkboxPanel = new Panel(new FlowLayout(FlowLayout.RIGHT)); 55. checkbox1 = new Checkbox(checkbox1Label); 56. checkbox1.setState(true); checkbox2 = new Checkbox(checkbox2Label); checkbox2.setState(false); checkbox3 = new Checkbox(checkbox3Label); checkbox3.setState(true); 57. checkboxPanel.add(checkbox1); checkboxPanel.add(checkbox2); checkboxPanel.add(checkbox3); 58. centerPanel.add(buttonsPanel,BorderLayout.WEST); centerPanel.add(checkboxPanel, BorderLayout.EAST); centerPanel.add(signaturePanel, BorderLayout.SOUTH); 59. return centerPanel; }

Explanation of numbered lines: 37.Panel is created containing buttons, check boxes, text field, and label. This is the center panel. 38.ChatFrame object is instantiated with passed object. 39.New Java AWT Panel object is created for the chat window center panel.

Chapter 7. Customized chat UI applet

147

40.Java AWT Button object is instantiated for placement on chat window. The previously declared button label text is used for the button. 41.An actionListener is added to the button. 42.Button selection is handled. 43.Previously declared text is sent to the chat window upon button selection. The formatMessage method is used to properly format text. 44.Second Java AWT Button object is instantiated for placement on chat window. The previously declared button label text is used for the button. 45.Third Java AWT Button object is instantiated for placement on chat window. The previously declared button label text is used for the button. 46.Fourth Java AWT Button object is instantiated for placement on chat window. The previously declared button label text is used for the button. 47.A new Java AWT Panel object is created for previously declared Java AWT Button objects. 48.Buttons are added to the Panel. 49.A new Java AWT Panel object is created for the signature field and label. FlowLayout is used to place objects side by side as placed. 50.Java AWT TextField object is instantiated with a size of 60 (columns). 51.Java AWT Label object is instantiated with previously declared text. 52.Label and TextField objects are added to Panel. 53.New Java AWT Panel object is created for Label/TextField panel. This is used for proper alignment in chat window. 54.New Java AWT Panel object is created for check boxes. 55.Java AWT Checkbox objects are instantiated with previously declared text. 56.Checkbox behavior is set. 57.Checkboxes are added to the new Panel. 58.Panels are added to the main panel created in the method. 59.The main panel is returned by method. This represents the center panel in the chat window.

getTimeStamp
60. private String getTimeStamp() { int hours = m_date.getHours(); int minutes = m_date.getMinutes(); if (minutes < 10) { return hours + ":" + "0" + minutes+ " ";

148

Working with the Sametime Client Toolkits

} } }

else { return (""+hours + ":" + minutes+ " ");

Explanation of numbered line: 60.The getTimeStamp method assembles a time/date value to be added to a message.

formatMessage
61. private String formatMessage(String msg) { 62. StringBuffer sbMessage = new StringBuffer(msg); 63. if(CustomizeChatFactory2.this.checkbox1.getState()) { sbMessage.insert(0, this.getTimeStamp()); } 64. if(CustomizeChatFactory2.this.checkbox3.getState()) { sbMessage.append(smiley); } 65. if(CustomizeChatFactory2.this.checkbox2.getState()) { sbMessage.append(beginSignature + textfield1.getText() + endSignature); } 66. return sbMessage.toString(); }

Explanation of numbered lines: 61.The formatMessage method centralizes the process of formatting chat text according to custom selections (checkboxes and signature field) in the chat window. 62.StringBuffer object is created to work with morphing text. It is initialized with text passed into method. 63.Timestamp is added to chat text if associated check box is selected. 64.Smiley text is added to chat text if associated check box is selected. 65.Signature text is added from TextField to chat text if associated check box is selected. 66.The newly formatted text is used as the return value of the method. The StringBuffer is converted to a String object via the toString method.

createLogoPanel
67. private Panel createLogoPanel(String logo) { 68. Panel p = new ImagePanel(getLogoURL(logo));

Chapter 7. Customized chat UI applet

149

69. }

p.setBackground(new Color(0xFFcc00)); return p;

Explanation of numbered lines: 67.The CreateLogoPanel method is used to construct a panel containing an image. 68.The ImagePanel class is used for the logo panel. 69.The background of the logo panel is set.

getLogoURL
70. private URL getLogoURL(String logo) { URL url = null; try { 71. url = new URL(m_applet.getCodeBase(), logo); } catch(MalformedURLException e) { e.printStackTrace(); } return url; } }

Explanation of numbered lines: 70.The getLogoURL method calculates the complete URL for a image file. 71.The logo URL is constructed using the image filename and the applet codebase. In 7.6.2, Loading the logo from a jar file on page 172 we discuss how the logo image can be loaded from a jar file.

7.4 CustomizeChatUI2
The CustomizeChatUI2 class is the Java applet presented to the user. It contains the text field for entering invitees, the list box with meeting type, the buttons, and the check box for including Invite Dialog or not. The class appropriately extends the Applet class. In addition, it implements the methods shown in the next section.

7.4.1 Methods
The following methods are found in CustomizeChatUI2:

150

Working with the Sametime Client Toolkits

init - The basic init method of the Applet class. It is called to initialize the applet. The following steps are performed: a. A new Sametime session is created (if necessary) and initialized. b. The initializeLayout method is called to set up Applet user interface. c. The ServerName is calculated from Applet codebase. d. The login name and password are retrieved from applet parameters. e. A new Community Service object is created. f. The ChatUI object is initialized; assigning our CustomizeChatFactory class to it. g. The CommUI object is set up. destroy - The standard destroy method of the Applet class. It is called when the applet (browser) is closed or a new page is loaded. loggedIn - Method triggered when/if user successfully logs onto the Sametime Server. It is derived from the community package, and made available by implementing LoginListener. The send button is enabled upon login. loggedOut - Method triggered when/if user unsuccessfully logs onto the Sametime Server. It is made available by the community package, and implementing LoginListener. The send button is disabled if not logged on. actionPerformed - Handles the action of pressing the send button. Made available by implementing ActionListener. This method parses the invitee names (via breakString method) and calls the Resolve method on the CommUI object for each name. A resolved event is triggered if the names resolve with no problems; otherwise a resolveFailed event is triggered. The Send button is disabled. resolved - Triggered by the actionPerformed event; seeks to resolve invitee names with the Sametime Server. The resolved user names are added to a Vector object; once all names have been resolved a meeting is created with the resolved names. resolveFailed - Triggered when/if names are not resolved; error message is displayed. createMeeting - Triggered by the resolved and resolveFailed methods. The createMeeting method is derived from the base ChatUI class. A one-on-one meeting is created for meetings with only one other user. Otherwise, the meeting type selection (from selection list in applet) is used to start the appropriate meeting. launchMeeting - Meeting is launched from Applet in its own window; this is made available by implementing the MeetingListener interface from the ChatUI package.

Chapter 7. Customized chat UI applet

151

meetingCreationFailed - Triggered if meeting cannot be created/launched. Made available by the MeetingListener interface from the ChatUI package. UrlClicked - Triggered when URL is clicked. URLs may be presented in the Chat window or in our custom menu selections. The clicking of a URL triggers a URLClickEvent, which triggers urlClicked. This is available by implementing the URLClickListener Interface. InitializeLayout - The initializeLayout method is a custom method added to perform the initial steps of setting up the applet presentation. The choice field is added, along with values added to it. Also, the panels, buttons, and check box are added. The actionListener is assigned to the button, and the default behavior (disabled) for the button is set. BreakString - The breakString method is a custom method for working with the comma separated values in the invitee list entered in the applet by the user. A String array is created and returned containing the separate values. The StringTokenizer object is used to work with the values. We now walk through the full source code for the class.

7.4.2 CustomizeChatUI2.java
The complete code for the class is listed here. We have numbered important lines in the code and we explain those lines after each code element.

Imports and class declaration


import java.applet.Applet; import java.awt.*; import java.awt.event.*; import java.net.*; import java.util.Vector; import java.util.StringTokenizer; import com.lotus.sametime.chatui.*; import com.lotus.sametime.core.comparch.*; import com.lotus.sametime.core.types.STUser; import com.lotus.sametime.community.*; import com.lotus.sametime.commui.*; 1.import com.lotus.sametime.core.constants.MeetingTypes; public class CustomizeChatUI2 extends Applet implements LoginListener, MeetingListener, UrlClickListener, ActionListener, CommUIListener {

152

Working with the Sametime Client Toolkits

2. private STSession m_session; 3. private ChatUI m_chatUI; 4. private CommUI m_commUI; 5. private int m_namesToResolve; 6. private Vector m_meetingUsers = new Vector(); 7. private TextField textfield1; 8. private Checkbox checkbox1; 9. private Button button1; 10. private Label label1; 11. private String label1Text = "Invitees names (divided by comma ','):"; 12. private String checkbox1Text = "Show Invite Dialog"; 13. private String button1Text = "Start Chat";

Explanation of numbered lines: 1. The MeetingTypes class is imported to use with selection list applet. The list allows the user to choose the type of meeting to initiate. The constants from the MeetingTypes class are used by the code to create the appropriate meeting. 2. The Sametime Session object is available/used throughout the code. 3. The ChatUI object is used throughout the code; it is used to work with the chat window. 4. The CommUI object is used throughout the code. 5. A primitive integer variable is used to track number of remaining names to be resolved. 6. A Vector object is used to store (resolved) user names for the meeting. 7. The AWT TextField allows the user to enter the invitee names. 8. The AWT Checkbox signals whether the invite dialog box appears after selecting send. 9. The AWT Button initiates the meeting request. 10.The AWT Label object is used to display text in applet. 11.The text for the label is created. 12.The text for the check box is created. 13.The text for the button is created.

init
14. public void init() { try { 15. m_session = new STSession("ChatUIApplet"); 16. m_session.loadAllComponents();

Chapter 7. Customized chat UI applet

153

17. m_session.start(); } catch(DuplicateObjectException e) { e.printStackTrace(); } 18. initializeLayout(); 19. String serverName = getCodeBase().getHost().toString(); 20. String loginName = getParameter("loginName"); String password = getParameter("password"); 21. CommunityService comm = (CommunityService)m_session.getCompApi(CommunityService.COMP_NAME); 22. comm.addLoginListener(this); 23. comm.loginByPassword(serverName, loginName, password); 24. m_chatUI = (ChatUI)m_session.getCompApi(ChatUI.COMP_NAME); 25. m_chatUI.addUrlClickListener(this); 26. m_chatUI.addMeetingListener(this); 27. m_chatUI.setChatFactory(new CustomizeChatFactory2(m_session, this)); 28. m_commUI = (CommUI)m_session.getCompApi(CommUI.COMP_NAME); 29. m_commUI.addCommUIListener(this); }

Explanation of numbered lines: 14.The init method is standard for applets; it contains initialization logic for the applet. 15.A new Sametime Session is created. 16.All Sametime components are loaded for the session. 17.The Sametime session is started. 18.The initializeLayout method is called to set up the user interface. 19.The Sametime Server name is retrieved via the code base of the applet. 20.The login name is retrieved from an applet parameter (HTML PARAM tag). 21.A new CommunityService object is created. It is a core service required to log in/out of a Sametime Server. 22.A loginListener is added to the CommunityService object. The loggedIn and loggedOut events are fired as necessary. 23.The loginByPassword method of the CommunityService class is called to log in the current user. The login name and password from the applet parameters are used along with the calculated Sametime Server name. 24.A new ChatUI object is created. It allows the creation and participation of Sametime meetings without dealing with the low-level protocols involved. The invite dialog box is included as well. 25.A urlClickListener is added to the ChatUI object to handle the selection of URLs within a chat dialog.
154

Working with the Sametime Client Toolkits

26.A meetingListener is added to the ChatUI object. This fosters the creation and launching of Sametime meetings. 27.Our custom Chat factory class is assigned to the ChatUI object. 28.The CommUI object is instantiated. It provides various services, most notable is the ability to resolve names for attending Sametime meetings. This function is used to resolve names entered by user into applet field. 29.A listener is assigned to the CommUI object to handle community UI events.

destroy
30. public void destroy() { 31. CommunityService comm = (CommunityService) m_session.getCompApi(CommunityService.COMP_NAME); 32. comm.logout(); 33. m_session.stop(); 34. m_session.unloadSession(); }

Explanation of numbered lines: 30.The destroy method is a standard applet method. It is executed when the applet is destroyed/unloaded. 31.The CommunityService object is destroyed along with applet. 32.The user is logged out of Sametime Server when applet is destroyed. 33.The Sametime session is stopped when applet is destroyed. 34.All Sametime components are unloaded when applet is destroyed.

loggedIn
public void loggedIn(LoginEvent event) System.out.println("LOGGED IN"); button1.setEnabled(true); } {

loggedOut
public void loggedOut(LoginEvent event) { System.out.println("LOGGED OUT. REASON=" + event.getReason()); button1.setEnabled(false); }

Chapter 7. Customized chat UI applet

155

actionPerformed
35. public void actionPerformed(ActionEvent p1) { 36. String[] userNames = breakString(textfield1.getText(), ","); 37. if (userNames == null || userNames.length == 0) { return; } 38. button1.setEnabled(false); 39. m_namesToResolve = userNames.length; 40. for (int i=0; i < m_namesToResolve; i++) { m_commUI.resolve(userNames[i].trim()); } }

Explanation of numbered lines: 35.The clicking of the send button is handled. 36.A String array is constructed with invitee names by way of the breakString method. 37.Execution halts if no names are entered. 38.The send button is disabled since it has just been selected. 39.The number of names to resolve is set to the number of values in the String array. 40.All names in the String array are processed with the resolve method.

resolved
41. public void resolved(CommUIEvent event) { 42. STUser resolved = event.getUser(); 43. m_meetingUsers.addElement(resolved); 44. if (--m_namesToResolve == 0) { createMeeting(); } }

Explanation of numbered lines: 41.The resolved method is called if a name is successfully resolved. 42.The username is retrieved from the event. 43.The resolved name is added to the Vector object. 44.The meeting begins if there are no more names to resolve.

156

Working with the Sametime Client Toolkits

resolveFailed
public void resolveFailed(CommUIEvent event) { System.out.println("resolve Failed "+ event.getName() + ":" + event.getReason()); if (--m_namesToResolve == 0) { createMeeting(); } }

createMeeting
45. private void createMeeting() { 46. button1.setEnabled(true); 47. String meetingType = "Chat"; if ((meetingType == "Chat") && m_meetingUsers.size() == 1) { 48. STUser imPartner = (STUser)m_meetingUsers.firstElement(); 49. m_chatUI.create1On1ChatById(imPartner); 50. m_meetingUsers.removeAllElements(); return; } MeetingTypes type = null; 51. type = MeetingTypes.ST_CHAT_MEETING;; 52. STUser[] invitees = new STUser[m_meetingUsers.size()]; m_meetingUsers.copyInto(invitees); 53. boolean showInviteDlg = checkbox1.getState(); 54. m_chatUI.createMeeting(type, "", "", showInviteDlg, invitees); m_meetingUsers.removeAllElements(); }

Explanation of numbered lines: 45.The createMeeting method is triggered when all names have been processed/resolved. 46.The send button is reset. 47.The meeting type is set to chat; chat is the only meeting type used in this example. 48.The first username is used if the meeting is a chat or one-on-one meeting. 49.A one-on-one chat session is created. 50.All other users are removed from Vector. 51.Meeting type set accordingly to chat. 52.An array of Sametime users is created using Vector of names.

Chapter 7. Customized chat UI applet

157

53.The value from the 'show meeting dialog' is retrieved from applet. This signals whether meeting invitee dialog box is shown (True/selected) or not. 54.A new chat Sametime meeting is created.

launchMeeting
55. public void launchMeeting(MeetingInfo meetingInfo, URL url) { getAppletContext().showDocument(url, meetingInfo.getDisplayName()); }

Explanation of numbered line: 55.The launchMeeting method is called when a meeting is started. The meeting is opened in its own window from the applet.

meetingCreationFailed
56. public void meetingCreationFailed(MeetingInfo meetingInfo, int reason) System.err.println("Failed to create the meeting: " + reason); } {

Explanation of numbered line: 56.A message is displayed in the console if the meeting failed to start.

urlClicked
57. public void urlClicked(UrlClickEvent event) { 58. URL url; 59. String urlString = event.getURL(); try { 60. url = new URL(urlString); } catch(MalformedURLException e) { System.err.println("URL Clicked: MALFORMED URL"); return; } 61. getAppletContext().showDocument(url); }

Explanation of numbered lines: 57.The selection of a URL triggers the urlClicked event. 58.A new URL object is created. 59.The URL is retrieved from the event.

158

Working with the Sametime Client Toolkits

60.A new URL object is instantiated using the passed URL. 61.The URL is opened in its own window from the applet.

initializeLayout
62. void initializeLayout() { 63. setBackground(Color.white); 64. Panel p = new Panel(new GridLayout(2,1)); Panel p1 = new Panel(); 65. button1 = new Button(button1Text); 66. p1.add(button1); 67. checkbox1 = new Checkbox(checkbox1Text, true); 68. p1.add(checkbox1); 69. Panel p2 = new Panel (new BorderLayout()); 70. label1 = new Label(label1Text); 71. p2.add(label1,BorderLayout.CENTER); 72. textfield1 = new TextField(40); 73. p2.add(textfield1,BorderLayout.SOUTH ); 74. p.add(p2); p.add(p1); 75. add(p); 76. button1.addActionListener(this); 77. button1.setEnabled(false); }

Explanation of numbered lines: 62.The initializeLayout method sets up the applet user interface. 63.The applet background is set as white. 64.New Java AWT Panel object is created for applet layout. 65.A new AWT Button object is created to initiate meeting. The previously declared text is used for the button label. 66.Button is added to the panel. 67.A new AWT Check box object is created for the choice of whether invitee button is displayed in chat window or not. 68.Checkbox is added to the panel. 69.A new AWT Panel is created for label and text fields. 70.Label object is instantiated with previously declared text. 71.Label is added to panel. 72.TextField object is instantiated with size of 40 (columns). 73.TextField is added to panel.

Chapter 7. Customized chat UI applet

159

74.Panels added to main panel. 75.Main panel is added to the applet user interface. 76.ActionListener is assigned to the send button. 77.Send button is enabled.

breakString
78. protected String[] breakString(String toBreak, String separator) { String[] result = null; if (toBreak != null && !toBreak.equalsIgnoreCase("")) { if (separator == null || separator.equalsIgnoreCase("")) { result = new String[1]; result[0] = toBreak; }else { StringTokenizer stk = new StringTokenizer(toBreak, separator); result = new String[stk.countTokens()]; for (int i = 0; i < result.length && stk.hasMoreTokens(); i++) result[i] = stk.nextToken(); } } return result; }

Explanation of numbered line: 78.The breakString method parses a string value using the specified separator. A StringTokenizer object is used to streamline the process. This concludes our walk though of the CustomizeChatUI2 class. We continue with our last class.

7.5 ImagePanel
The ImagePanel class is a special class for dealing with graphic files (logos) to be presented in one or more panels in our chat interface. The class takes advantage of the AWT package for dealing with the graphics.

7.5.1 Methods
The following methods are found in the ImagePanel class: ImagePanel - The constructor method retrieves the image file via its URL. A MediaTracker object is used to work with the image file.

160

Working with the Sametime Client Toolkits

Paint - The image is drawn on the panel. The width and height of both the panel and the image are used to properly present the graphic. getMinimumSize - A Dimension object is returned representing the minimum size for the graphic. The height and width of the image file are used to calcuate the minimum size. getPreferredSize - A Dimension object is returned representing the preferred size; it actually calls the getMinimumSize method and returns its value. We now walk through the full source code for the class.

7.5.2 ImagePanel.java
The complete code for the class is listed here. We have numbered important lines in the code and we explain those lines after each code element.

Imports and class declaration


import java.awt.*; import java.net.URL; 1.class ImagePanel extends Panel { static int m_imageNum = 1; 2. Image m_image = null; 3. public ImagePanel(URL url) { 4. m_image = Toolkit.getDefaultToolkit().getImage(url); 5. MediaTracker tracker = new MediaTracker(this); 6. tracker.addImage(m_image,m_imageNum++); try { 7. tracker.waitForAll(); } catch(InterruptedException e) { } }

Explanation of numbered lines: 1. Class is declared; it extends the main AWT Panel class. 2. An Image object is used to work with the logo file. 3. The constructor accepts a URL object. Supposedly, the URL object points to the logo file. 4. The Image object is instantiated with the passed image via its URL. 5. MediaTracker object is instantiated for the current class. It is used to work with media files such as images. 6. The image is added to the MediaTracker object. 7. The code waits for the image to be loaded into MediaTracker object.

Chapter 7. Customized chat UI applet

161

paint
8. public void paint(Graphics g) { 9. int xPos = (this.WIDTH/2 + m_image.getWidth(this)/2) ; 10. int yPos = (this.HEIGHT/2 - m_image.getHeight(this)/2) ; 11. g.drawImage(m_image, xPos, 0, this); }

Explanation of numbered lines: 8. The paint method displays the image in the Panel. 9. The x coordinate position is calculated using the image and panel dimensions. 10.The y coordinate position is calculated using the image and panel dimensions. 11.The image is displayed.

getMinimumSize
12. public Dimension getMinimumSize() { return new Dimension(m_image.getWidth(this), m_image.getHeight(this)); }

Explanation of numbered line: 12.The minimum size is set using the image settings.

getPreferredSize
13. public Dimension getPreferredSize() { return getMinimumSize(); }}

Explanation of numbered line: 13.The preferred size is set to the minimum size.

Once our three classes are compiled into class files; they are ready to be used in an applet. An applet requires a corresponding HTML file.

162

Working with the Sametime Client Toolkits

7.5.3 The HTML file


An example of an HTML file used to launch our CustomizeChatUI2 applet is shown in the following.
<html> <head> <title> CustomizeChatUI2 </title> </head> <body> <applet code=CustomizeChatUI2.class archive=uitest.jar width=300 height=90> <param name=loginName value=tpatton> <param name=password value=password> </applet> </body> </html>

The code attribute signals the base class for the applet. The base class is the class extending the required Applet class; in our case, this is the CustomizeChatUI2.class file. The archive parameter tells the system where to locate the referenced base class and any other necessary class files. Next, we dive deeper into the issues surrounding applet deployment.

7.6 Deployment considerations


A number of methods can be used to deploy our custom applet, including using an existing Sametime Server, existing Domino Server, non-Domino Web Server, in a Domino-based application, or locally. The last method is out-of-the-ordinary, but we take a brief look at all of the listed methods: Sametime server This is the most straightforward approach; the required applet files (jar and html) are placed on the Sametime Server in the html directory (or subdirectory). non-Sametime Domino server The required files are placed in the html subdirectory on the Domino Server, but the applet file must be properly signed since it does not originate from the same server it is accessing. The applet archive will need all necessary class files (all referenced Sametime

Chapter 7. Customized chat UI applet

163

classes) in addition to its own class files since the files are not available on the server. Web Server This is the same approach as a plain Domino Server. The files are placed in the appropriate directory (depending on Web Server platform) and the applet archive must be signed to allow it access to the Sametime Server. The applet archive will need all necessary class files (all referenced Sametime classes) in addition to its own class files since the files are not available on the server. Combination of Sametime and Web server HTML files can be placed on a non-Sametime server and the applet's code on the Sametime server. This is done by setting the applet's codebase attribute. Using this approach we do not have to sign the applet. This deployment option is used by the Sametime Links toolkit. You can read more about this in Chapter 12, The Sametime Links toolkit on page 355. Domino-based application The applet files may be placed in a Domino database (as an applet archive) or in a directory. Next, the applet is placed on a Domino design element. The details of this approach are covered in the next section. Locally (hard drive) This is a rare occurrence, but an applet may be used locally. This requires the applet archive (with all required files) and an HTML file for loading the applet. The applet archive/class files must be signed to access the Sametime Server. Now, we take a closer look at integrating our sample into a Domino application.

7.6.1 Integrating with a Domino application


The previous extension of the ChatUI class provides a lot of extra functionality, but it still needs to be deployed on a Web server and (possibly) integrated into a full-scale Web application. This section covers the details of integrating the example with a Domino-based Web application. One change to the applet code is necessary before using it with a Domino application. The change allows the login name and password from the host Domino application to be passed to the embedded applet. This alteration is not required, but it does streamline the user experience since the user does not have to enter a separate username and password for accessing Sametime. The code change involves the init method of the CustomizeChatUI2 class. The method called to log in is changed from loginByPassword to loginByToken ( line #23 from code explanation earlier in this section ). The line changes from:
comm.loginByPassword(serverName, loginName, password)

164

Working with the Sametime Client Toolkits

to:
comm.loginByToken(serverName, loginName, password)

The code change is not necessary if you simply want to test adding an applet to Domino, but it is used throughout the remainder of this section so we avoid having to hard code user names and passwords.
Note: We assume some knowledge of Domino development in the following. You will need Domino Designer to add the applet to a Domino database. Make sure that the ID you are using has the right to run agents on the Sametime server. If you just want to make a quick test, you can make a copy of the Sametime server.id file and switch to that ID file in Domino designer.

The applet will be added to the basic Discussion application/database that is included with all Domino installations. The applet will be added to the upper portion of the main discussion form displayed in Figure 7-3 on page 165.

Figure 7-3 Discussion format

The applet will be added to the top of the form above the subject field. This allows users to initiate a chat from the form. The first step is the creation of the Domino database container. Figure 7-4 shows the New Database dialog box presented in the Domino Designer client (CTRL-N). This allows the server, database title, database path/filename, template, and other options to be chosen.

Chapter 7. Customized chat UI applet

165

Figure 7-4 Creating a new Domino database

For this example, the database was created locally with the specified title and filename. The Discussion Notes & Web (R5.0) template was used to create it. This provides a complete application with main topic as well as response forms. The applet will be added to the Main Topic form, but first an applet resource is created. This allows the applet to be easily reused and maintained from a central location. Figure 7-5 shows the list of resources for the database, with Figure 7-6 showing the result of choosing the New Applet Resource button.

Figure 7-5 Applet Resources

166

Working with the Sametime Client Toolkits

Figure 7-6 New Applet Resource dialog box

The necessary archive file (which we called uitest.jar) is chosen from the file system. The creation of the jar file depends upon your environment; see Chapter 4, Installation and setup on page 71 for details on how to create a jar file from the IBM JDK or from VisualAge for Java. Select the OK button and a dialog box opens as shown in Figure 7-7. It accepts a name for the resource.

Figure 7-7 Assign name to applet resource

The customized chat window displays a logo. Normally this is a gif file that is loaded from the directory where the applet was loaded from. To make it available for an applet embedded in Domino we must add it as an Image resource. Click on Images under Resources in Domino Designer and import the logo.gif file as a resource. The next task is the placement of the applet on the proper form. The Main Topic form has been chosen, but it may be placed on others or all forms. Figure 7-8 on page 168 shows the Main Topic form opened in Domino Designer.

Chapter 7. Customized chat UI applet

167

Figure 7-8 Main Topic form in design mode

The applet is placed above the subject field. A new row is inserted in the table for the applet. The cursor is placed at the point of insertion, and the pass-thru HTML for the applet is inserted. You format text as pass-thru HTML by highlighting it and selecting Text -> Pass-Thru HTML in Domino Designer. Figure 7-9 on page 169 shows the Main Topic form with the necessary pass-thru HTML.

168

Working with the Sametime Client Toolkits

Figure 7-9 Main Topic form with applet pass-thru HTML

The Domino database and form must be properly configured to work with Sametime. We will cover these steps before dissecting the pass-thru HTML. Basically, three tasks should be completed to prepare the application for Sametime integration. These tasks are covered in more detail in Appendix A of the Sametime 2.5 Java Toolkit Developers Guide. The following tasks must be completed. 1. Copy the following Script Libraries from the Sametime Discussion (STDisc50.ntf) template installed with Sametime to our application. SametimeHost contains code to retrieve/calculate the Sametime Server address/name SametimeAgent SametimeClient SametimeStrings contains Sametime-relevant variables/constants. 2. Copy the following agents from the Sametime Discussion (STDisc50.ntf) template to our application. SametimeGetHost populates the SametimeHost field on the form; uses SametimeHost library. SametimePreWebQueryOpen SametimeWebQueryOpen

Chapter 7. Customized chat UI applet

169

3. Add the following three lines to the WebQueryOpen event for the Main Topic form. These lines run the previously listed agents when the form is opened in a browser client.
@Command([ToolsRunMacro]; "SametimePreWebQueryOpen"); @Command([ToolsRunMacro]; "SametimeWebQueryOpen"); @Command([ToolsRunMacro]; "SametimeGetHost")

Pass-thru HTML is used to place the applet on the form. Domino Designer does allow the embedding of Java applets via the Create->Java Applet menu selection. This approach causes problems with our applet, since the applet CODEBASE attribute is populated via a Domino field from our form. The embedding of applets on a form does not make the CODEBASE attribute accessible to be populated by a field value. It is only accessible via the properties info box for the embedded applet. For this reason, pass-thru HTML is used to properly set up our applet on the form. The complete pass-thru HTML follows:
<APPLET CODE="CustomizeChatUI.class" ARCHIVE="stchatui.nsf/ChatUI/$File/uitest.jar, sametime\toolkits\java\Bin\CommRes.jar, sametime\toolkits\java\Bin\STComm.jar" CODEBASE="http://[SametimeHost field]/" HEIGHT="100" WIDTH="300"> <PARAM NAME="loginName" VALUE="[loginName field]"> <PARAM NAME="password" VALUE="[SAMETIME_TOKEN field]"> </APPLET>

The listed HTML includes three new Domino fields, described in Table 7-1.
Table 7-1 New fields on Sametime-enabled Domino form
Field name SametimeHost Description Holds the server or host name; the field is computed-for-display with a default value of empty quotes (""). The WebQueryOpen event populates the field. Holds user name in Sametime; the field is computed-for-display with a default value of @UserName. The token used for Sametime login instead of the user password; the field is computed-for-display with a default value of empty quotes ("");

loginName SAMETIME_TOKEN

170

Working with the Sametime Client Toolkits

The three fields are inserted into the body of the applet pass-thru HTML. Here is a breakdown of the rest of the applet pass-thru HTML. CODE the applet base class. ARCHIVE the Java archive (jar) containing classes/resources; the value points to the previously created Java applet resource as well as the required Sametime toolkit jar files. WIDTH width of displayed applet. HEIGHT height of displayed applet. CODEBASE the starting point for located resources (archive). The applet is ready to be used after adding it to the form. Figure 7-10 shows a Main Topic loaded in a browser with the customized chat window open.

Figure 7-10 Results loaded in browser

Chapter 7. Customized chat UI applet

171

Tip: In this sample we followed the instructions from the Sametime 3.0 Java Toolkit Developers Guide, where you are instructed to use the Sametime-enabled teamroom template.

Instead, you can start with the Sametime Auth Skeleton (stskel.ntf) template, which is a minimized token-generation application. Follow these steps to modify the application: 1. Create a .nsf, and remove the design inheritance from the template. 2. Modify the access control to force authentication, and test the application. 3. Modify the Default form by replacing the embedded applet with your applet. 4. Provide needed parameters and test.

Tip 2: If you would rather get a token and feed it to a Sametime application yourself, you can modify the Domino database further by adding a form that can serve up the token as a response to an HTTP command like:
http://<sametime server>/stapp.nsf/GetUserAndToken?OpenForm

Use of this approach is shown in Appendix D, Sametime portlets on page 391.

Tip 3: Our Domino Sametime deployment sample requires that the client is a Web browser. If you want to Sametime-enable Domino application for Lotus Notes clients you can still launch an applet. However, the agent we use to get the token is only triggered for Web browsers, so you will have to change the logic if you want to use an applet. A better approach, in many cases, is to use the Sametime COM toolkit instead. We discuss that toolkit in Chapter 11, The COM toolkit on page 309.

7.6.2 Loading the logo from a jar file


As we discussed earlier, you must add the logo.gif file as an Image resource to the Domino database to make it available for the embedded applet. There is another way to the image file as well. When creating the jar file with the compiled Java classes, we can also add resources such as images and property files to the jar file. Thus we can add the logo.gif image file to the jar file. To load an image from a jar file we need to change our code slightly. Currently we do it like this:
URL url = new URL(m_applet.getCodeBase(), logo);

172

Working with the Sametime Client Toolkits

To load the image from the jar file we must instead use a line like this:
URL url = CustomizeChatFactory.class.getResource("logo.gif");

Using this approach gives you one file less to keep track of.

7.7 Extending the functionality


Our applet is good and user-friendly, but it is not flexible. That is, the canned messages available to the user are not user-defined. The user may choose a signature/tag line, but they must use pre-defined messages. This may be a problem given the nature of our global economy. A funny English phrase may not be so funny in German, and vice-versa. In this section we go one step further by allowing the user to define the messages and the labels of their respective buttons. The flexibility afforded by user-customization is great, but a large hurdle must be overcome before proceeding. User-defined data requires storage. The data must be stored when changed and in-between use, and reloaded when the user returns. Browser-based security introduces dicey areas for accessing a local drive. The Sametime Toolkit developers foresaw such problems by providing the Storage service. It stores user-related information as attributes directly on the Sametime server. Consequently, the stored data is available whenever (and wherever) you log into your Sametime server. The previous example is extended to provide the storage mechanism for custom messages and their respective buttons. The classes are renamed, appending Red to their class names; this avoids confusion with the previous example. Changes are made to the CustomizedChatFactory (now RedCustomizedChatFactory) class, and a new class is added to provide a user interface for entering the data. The new class is named RedStorageFrame. We take a look at RedStorageFrame first. The following list provides a description of each method in our new class. RedStorageFrame The constructor method accepts a Sametime session (STSession) object, creates/initializes the StorageService object, and calls the init method to set up the interface. AttrQueried This method must be used per the StorageServiceListener interface. It is called when an attribute has been queried from storage. AttrStored This method must be used per the StorageServiceListener interface. It is called when attribute values are stored. AttrUpdated This method must be used per the StorageServiceListener interface. It is called when an attribute has been updated.

Chapter 7. Customized chat UI applet

173

Init This method performs setup operations for the user interface. The user interface is a window with labels and field for the user data. The AWT package is utilized. LoadAttributes This method must be used per the StorageServiceListener interface. It is fired from the serviceAvailable event/method telling the system to load values/attributes from storage. loadValuesFromAttributes Values are loaded from the service. The values are loaded as one string, and parsed (on semi-colon). The resulting values are stored in a Vector object and assigned to fields set up in the init method. The position number in the Vector corresponds to a field in the user interface. serviceAvailable This method must be used per the StorageServiceListener interface. It is fired upon the initialization of the Storage Server; signalling it is available. serviceUnavailable This method must be used per the StorageServiceListener interface. It is fired upon the initialization of the Storage Server; signalling it is not available. storeSettings The storeSettings method is called when the user interface (window) is closed; this ensures any changes to the values are properly stored for reuse next time the user accesses the application. The complete code of the RedStorageFrame class is listed next.

7.7.1 RedStorageFrame.java
Here is the source code for our RedStorageFrame class. We have numbered important lines in the code and we explain those lines after each code element.

Imports and class definition


import java.awt.*; import java.awt.event.*; import java.applet.*; import java.io.*; import java.util.*; import java.net.URL; import com.lotus.sametime.core.comparch.STSession; import com.lotus.sametime.core.comparch.DuplicateObjectException; import com.lotus.sametime.core.constants.STError; import com.lotus.sametime.core.types.*; import com.lotus.sametime.community.*; 1. import com.lotus.sametime.storage.*; import com.lotus.sametime.commui.*; 2. class RedStorageFrame extends Frame implements StorageServiceListener { private STSession m_session;

174

Working with the Sametime Client Toolkits

3.

4.

private StorageService m_storageService; private TextField button1TextField; private TextField button2TextField; private TextField button3TextField; private TextField button4TextField; private TextField button1MessageTextField; private TextField button2MessageTextField; private TextField button3MessageTextField; private TextField button4MessageTextField; private Integer m_nReqID; private final static int ATT_KEY = 0xFFFF;

Explanation of numbered lines: 1. The storage package is imported; it contains all necessary classes for dealing with the storage service. 2. The class is declared; it implements the StorageServiceListener interface to work with the storage service. 3. A new storage service object is created. 4. An attribute key is needed to work with data in via the storage service.

StorageFrame constructor method


5. public StorageFrame ( STSession session ) { super("Storage Frame"); m_session = session; m_storageService = (StorageService)m_session.getCompApi(StorageService.COMP_NAME); m_storageService.addStorageServiceListener(this); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { storeSettings(); dispose(); } }); init(); }

6. 7. 8. 9.

Explanation of numbered lines: 5. The constructor method contains code for instantiating the storage service for our use. 6. The storage service object is instantiated. 7. A storage service listener object is assigned to our class.
175

Chapter 7. Customized chat UI applet

8. A window listener is added to respond accordingly when the window is closed. 9. The attributes are stored upon window closing.

attrQueried
public void attrQueried ( StorageEvent e ) { if (m_nReqID == e.getRequestId()) { 10. if (e.getRequestResult() == STError.ST_OK) { 11. String temp = e.getAttrList().toString(); 12. int tempInt = temp.lastIndexOf(":"); 13. String temp3 = temp.substring(tempInt+1, temp.length()-1); 14. loadValuesFromAttribute(temp3); } else { System.out.println("Could not load attributes."); } } }

Explanation of numbered lines: 10.Execution proceeds only if no error is incurred. 11.The attribute list is retrieved as a string. 12.We need the data to the right of the last colon, so the colon is located. The attribute uses the following form:
[key:65535 value: text]

where the key is assigned upon storage and the text is the actual attribute value. We only need the text. 13.The text is extracted using the location of the colon as the starting point and proceeding to the character before the final brack (]). 14.The extracted text is sent to the loadValuesFromAttribute method to populate the user interface.

attrStored
public void attrStored ( StorageEvent e ) { if ((m_nReqID == e.getRequestId()) && (e.getRequestResult() != STError.ST_OK)) { System.out.println("Could not store attributes."); } }

176

Working with the Sametime Client Toolkits

attrUpdated
public void attrUpdated ( StorageEvent e ) { }

Note: We are setting up four buttons, four text fields, and so on in the init methods. This means that there is a lot of repetitive code. We show you the code for the first button, for the first entry field, and so on, and remove the repetitive code for the additional elements.

init
public void init ( ) { this.setLayout ( new BorderLayout() ); button1TextField = new TextField ( "button1" ); ..... button1MessageTextField = new TextField ( "MessageText1" ); ..... Label button1Label = new Label ( "Button 1" ); ..... Label button1MessageLabel = new Label ( "Message 1" ); ..... Panel button1Panel = new Panel ( new BorderLayout() ); ..... Panel tPanel1 = new Panel ( new FlowLayout() ); ..... tPanel1.add ( button1Label ); tPanel1.add ( button1TextField ); tPanel1.add ( button1MessageLabel ); tPanel1.add ( button1MessageTextField ); ..... button1Panel.add ( tPanel1 , BorderLayout.CENTER ); ..... Panel midPanel = new Panel ( new BorderLayout() ); midPanel.add ( button2Panel, BorderLayout.NORTH ); midPanel.add ( button3Panel, BorderLayout.SOUTH ); add ( button1Panel , BorderLayout.NORTH ); add ( midPanel , BorderLayout.CENTER ); add ( button4Panel , BorderLayout.SOUTH ); pack(); Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); setLocation((int)( ( d.width - getSize().width ) /2 ) , (int)( ( d.height - getSize().height ) /2 ) ); }

Chapter 7. Customized chat UI applet

177

loadAttributes
public void loadAttributes ( ) { 15. m_nReqID = m_storageService.queryAttr(ATT_KEY); }

Explanation of numbered line: 15.The firing of the loadAttributes method triggers the query of our attribute (assigned key) from the storage service.

loadValuesFromAttribute
public void loadValuesFromAttribute ( String attr ) { if (attr.equalsIgnoreCase("")) { 16. button1TextField.setText("button1"); button2TextField.setText("button2"); button3TextField.setText("button3"); button4TextField.setText("button4"); button1MessageTextField.setText("button message 1"); button2MessageTextField.setText("button message 2"); button3MessageTextField.setText("button message 3"); button4MessageTextField.setText("button message 4"); } else { String attribute; String value; 17. Vector values = new Vector(); 18. StringTokenizer tokenizer = new StringTokenizer(attr,";"); 19. while ( tokenizer.countTokens() > 0 ) { 20. values.addElement (tokenizer.nextToken()); } if ( values.size() > 0 ) { 21. button1TextField.setText((String)values.elementAt(0)); if ( values.size() > 1 ) button2TextField.setText((String)values.elementAt(1)); if ( values.size() > 2 ) button3TextField.setText((String)values.elementAt(2)); if ( values.size() > 3 ) button4TextField.setText((String)values.elementAt(3)); if ( values.size() > 4 ) button1MessageTextField.setText((String)values.elementAt(4)); if ( values.size() > 5 ) button2MessageTextField.setText((String)values.elementAt(5)); if ( values.size() > 6 ) button3MessageTextField.setText((String)values.elementAt(6)); if ( values.size() > 7 )

178

Working with the Sametime Client Toolkits

button4MessageTextField.setText((String)values.elementAt(7)); } } }

Explanation of numbered lines: 16.Text fields are added to the window with default values if no values are found in the storage service. 17.If the attribute does contain values, a Vector object is created to stored the parsed values. 18.A StringTokenizer object is created using the attribute string and a semicolon as the separator. 19.The resulting StringTokenizer object is traversed with each value stored in the Vector. 20.Individual values are stored in the Vector. 21.Vector elements are used to populate user interface text fields.

serviceAvailable
public void serviceAvailable ( StorageEvent e ) { 22. loadAttributes(); }

Explanation of numbered line: 22.The loadAttributes method is called if the storage service is available.

serviceUnavailable
public void serviceUnavailable ( StorageEvent e ) { System.out.println("Storage Service is unavailable."); }

storeSettings
public void storeSettings ( ) { 23. StringBuffer buffer = new StringBuffer(); 24. buffer.append(button1TextField.getText()); 25. buffer.append(" ; "); buffer.append(button2TextField.getText()); buffer.append(" ; "); buffer.append(button3TextField.getText()); buffer.append(" ; "); buffer.append(button4TextField.getText());

Chapter 7. Customized chat UI applet

179

26. 27. } }

buffer.append(" ; "); buffer.append(button1MessageTextField.getText()); buffer.append(" ; "); buffer.append(button2MessageTextField.getText()); buffer.append(" ; "); buffer.append(button3MessageTextField.getText()); buffer.append(" ;"); buffer.append(button4MessageTextField.getText()); STAttribute attribute = new STAttribute(ATT_KEY, buffer.toString()); m_nReqID = m_storageService.storeAttr(attribute);

Explanation of numbered lines: 23.A new StringBuffer object is created to store our values. 24.Text from each TextField is added to the StringBuffer object. 25.Individual values are separated by semicolons. 26.A new STAttribute object is created with the value in the StringBuffer object. It contains all data values separated by semicolons. 27.The new attribute is stored.

7.7.2 Changes in the factory class


The other change to our code occurs in the CustomizeChatFactory class (now named RedCustomizeChatFactory). The class is altered to reflect our use of the Storage Service. The class now implements StorageServiceListener to take advantage of the service. In addition, the user interface is manipulated using data from the storage service. The value for each of the four custom message buttons is read from the storage service and assigned to the appropriate button, the label text is assigned to the button face, and the message text is displayed once the button is selected. The main alteration of our CustomizeChatFactory class is the addition of the loadValuesFromAttribute method. This performs the same function as described in the details of the StorageFrame class, but the code is different. The values are loaded/parsed from the storage service, and the results are used for the button labels in the user interface and the messages sent upon button selection. Here is the code for the method.
public void loadValuesFromAttribute ( String attr ) { Vector values = new Vector(); StringTokenizer tokenizer = new StringTokenizer(attr,";"); while (tokenizer.countTokens() > 0) { values.addElement(tokenizer.nextToken());

180

Working with the Sametime Client Toolkits

} button1Label = button2Label = button3Label = button4Label = button1Message button2Message button3Message button4Message }

(String)values.elementAt(0); (String)values.elementAt(1); (String)values.elementAt(2); (String)values.elementAt(3); = (String)values.elementAt(4); = (String)values.elementAt(5); = (String)values.elementAt(6); = (String)values.elementAt(7);

Notice that the code is similar to its counterpart in the RedStorageFrame class, but the values are used differently. Also, the values are not altered in the chat dialog window. This is only available from the applet initiating the chat session. The new user interface is displayed in the next two figures. The applet interface has a new button to launch the RedStorageFrame for working with stored values, as shown in Figure 7-11.

Figure 7-11 New applet interface with storage service button

Figure 7-12 User-defined buttons and messages

Chapter 7. Customized chat UI applet

181

Figure 7-13 Using the new buttons

7.8 How to use with other toolkit UI elements


We have a great chat UI applet customized to our liking, but it is not worth much as a standalone applet. Here we explain how you replace the default chat window with your chat window in the other Java Toolkit UI elements. To include the use of your customized chatui window in an application, the following three things must be performed: 1. Make sure the following package is imported in your class:
com.lotus.sametime.chatui.*

2. Get a reference to the chatui like this:


m_chatUI = (ChatUI)m_session.getCompApi(ChatUI.COMP_NAME);

3. Tell the chatui to use another factory class, like this:


m_chatUI.setChatFactory(new RedCustomizeChatFactory(m_session, this ));

You must supply an instance of your chat factory class as a parameter to the setChatFactory method in the chatui object. If you want to make a quick test of this you can modify the LiveNames Applet sample included with the toolkit to use your CustomizeChatUI.

182

Working with the Sametime Client Toolkits

We did this and found out that our initial choice of adding the Storage Service button to the launch window was not such a great idea because we do not use this window when the chat ui is launched from one of the other toolkit UI objects. However, the button can easily be moved to the chat window, or you can simply invoke the window (RedStorageFrame) for setting your predefined messages from a menu option. We will leave it as an exercise for you to do this modification.
Note: We modifed the LiveNames sample to test the new chat UI with VisualAge for Java 4.0. However, we initially got an error when we added the import statement for the chatui package to the LiveNamesApplet class. The error message said that the ResolveListener was ambiguous. When we looked in the chatui package in VisualAge for Java, there indeed was a ResolveListener in that package (as well as in the lookup package where it is supposed to be). We deleted the ResolveListener from the chatui package and the sample worked, but read on because this is not a good solution.

If you use the IBM JDK to compile the sample, no errors will be reported. The problem seems to be due to a bug in VisualAge for Java. There actually is a ResolveListener interface in the chatui package, but it is not public and thus not accessible for the Java toolkit developers. VisualAge for Java should not make the ResolveListener in the chatui package visible.

However, deleting the ResolveListener will cause the Sametime toolkit to break down in other places.
If you want to try our workaround in VisualAge for Java, make sure that you have versioned the classes in the Sametime chatui package first. Bring back the versioned edition of the chatui package before you attempt any other Sametime development. We will now go on to our last example in this chapter, where we pass a Sametime token between two applets.

7.9 Passing a token between applets


In 7.6.1, Integrating with a Domino application on page 164 we saw how the credentials of a Sametime user could be verified by a token instead of the user ID/password combination. This way the user did not have to log in twice (first to Domino and then to Sametime). But what if you have an application consisting of several applets that does not include Domino? Each individual applet must log

Chapter 7. Customized chat UI applet

183

into Sametime, and to avoid having the user prompted every time a new applet is launched you have to figure out how to get the token from the first applet and pass it on to the other applets in the application. In this section we walk through an example of doing this. In this section we cover the details of passing login data between applets. One applet will load and log into a Sametime Server, and the login information will be made available to other applets (Web pages). The key piece of information is the token. A token for a user can be accessed by way of the Token service (com.lotus.sametime.token package). A class implements the TokenServiceListener interface with the following methods for dealing with tokens: generateTokenFailed - This method/event fires if a call to the generateToken method fails to produce a token. The only parameter is a TokenEvent object. tokenGenerated - This method/event fires upon a successfully generateToken call. The one parameter is a TokenEvent object; it provides access to the specifics of the generated token. Our RedCustomizeChatUI application is used to demonstrate the specifics of dealing with tokens. In addition to the token, the class will also make the username and server available via get methods. These methods are accessible from JavaScript. The changes to the RedCustomizeChatUI class are listed first. The changes consist of implementing TokenServiceListener, adding the required methods, calling generateToken from the login method, and adding fields for the data values and corresponding get/set methods. The class code is listed next, with changes highlighted and explained. We only show new or changed methods. For an explanation of other methods in the class, see 7.4.2, CustomizeChatUI2.java on page 152.

Imports and class definition


import java.applet.Applet; import java.awt.*; import java.awt.event.*; import java.net.*; import java.util.Vector; import java.util.StringTokenizer; import com.lotus.sametime.chatui.*; import com.lotus.sametime.core.comparch.*; import com.lotus.sametime.core.types.STUser; import com.lotus.sametime.community.*; import com.lotus.sametime.commui.*; import com.lotus.sametime.core.constants.MeetingTypes; import com.lotus.sametime.core.types.*;

184

Working with the Sametime Client Toolkits

1. import com.lotus.sametime.token.*; public class RedCustomizeChatUI extends Applet implements MeetingListener, UrlClickListener, CommUIListener, LoginListener, ActionListener, 2. TokenServiceListener { private STSession m_session; private ChatUI m_chatUI; private CommUI m_commUI; private int m_namesToResolve; private Vector m_meetingUsers = new Vector(); private TextField textfield1; private Button button1; private Checkbox checkbox1; private Label label1; private String label1Text="Invitees (divided by comma ','):"; private String checkbox1Text = "Show Invite Dialog"; private String button1Text = "Start Chat"; private StorageFrame m_attributeFrame; private Button storageButton; 3. private TokenService m_tokenService; 4. private String token = ""; private String username; private String serverName = "";

Explanation of numbered lines: 1. The necessary token service classes are made available in our code. 2. The TokenServiceListener is added to our class. 3. A TokenService object is created for later use. 4. The member fields are declared; these will hold values for username, token, and server. They are declared as private to prevent direct access. A corresponding get method is provided for each field.
5.

generateTokenFailed
6. public void generateTokenFailed( TokenEvent e ) { System.out.println("Generate Token Failed."); System.out.println(e.toString()); }

Chapter 7. Customized chat UI applet

185

Explanation of numbered line: 6. The generateTokenFailed event fires when/if a call to the generateToken method is unsuccessful.

getServerName
7. public String getServerName() { return serverName; }

Explanation of numbered line: 7. A public get method for the server name field is provided. It returns the value stored in the serverName field.

getToken
8. public String getToken() { return token; }

Explanation of numbered line: 8. A public get method is provided for the token field. It returns the value stored in the token field.

getUsername
9. public String getUsername() { return username; }

Explanation of numbered line: 9. A public get method is provided for the username field. It returns the value stored in the username field.

handleException
private void handleException(Throwable exception) { exception.printStackTrace(System.out); }

186

Working with the Sametime Client Toolkits

init
public void init() { try { m_session = new STSession("ChatUIApplet"); m_session.loadAllComponents(); m_session.start(); }catch(DuplicateObjectException e) { e.printStackTrace(); } initializeLayout(); 10. setServerName ( getCodeBase().getHost().toString() ); String loginName = getParameter("loginName"); String password = getParameter("password"); CommunityService comm = (CommunityService) m_session.getCompApi(CommunityService.COMP_NAME); comm.addLoginListener(this); comm.loginByPassword(this.getServerName(), loginName, password); m_chatUI = (ChatUI)m_session.getCompApi(ChatUI.COMP_NAME); m_chatUI.addUrlClickListener(this); m_chatUI.addMeetingListener(this); m_attributeFrame = new RedStorageFrame(m_session); m_attributeFrame.setVisible(false); m_chatUI.setChatFactory( new CustomizeChatFactory(m_session, this )); m_commUI = (CommUI)m_session.getCompApi(CommUI.COMP_NAME); m_commUI.addCommUIListener(this); 11. m_tokenService = (TokenService) m_session.getCompApi(TokenService.COMP_NAME); 12. m_tokenService.addTokenServiceListener( this ); }

Explanation of numbered lines: 10.The private set method for the serverName field is called with value from the current environment. 11.The TokenService object is instantiated. 12.The TokenService listener is assigned to our class. This activates the generateTokenFailed and tokenGenerated methods. They await a call to generateToken.

loggedIn
public void loggedIn(LoginEvent event) { button1.setEnabled(true); 13. m_tokenService.generateToken(); }

Chapter 7. Customized chat UI applet

187

Explanation of numbered line: 13.The generateToken method is called when/if a user successfully logs onto the Sametime Server. This call triggers the other related events: either tokenGenerated or generateTokenFailed.

setServerName
14. private void setServerName(String newServerName) { serverName = newServerName; }

Explanation of numbered line: 14.The private set method for the serverName field. The method is declared private to prevent outside access.

setToken
15. private void setToken(String newToken) { token = newToken; }

Explanation of numbered line: 15.The private set method for the token field.

setUsername
16. private void setUsername(java.lang.String newUsername) { username = newUsername; }

Explanation of numbered line: 16.The private set method for the username field.

tokenGenerated
17. 18. 19. 20. public void tokenGenerated( TokenEvent e ) { Token token = e.getToken(); setToken(token.getTokenString()); setUsername(token.getLoginName()); }

188

Working with the Sametime Client Toolkits

Explanation of numbered lines: 17.The tokenGenerated method is triggered if a call to the generateToken method is successful. 18.A Token object is populated by way of the TokenEvent object passed into the method. 19.The token field of the current object is set. 20.The username field of the current object is set. The class may now be used (with other relevant classes) in a Web page, with JavaScript providing access to the new fields. Public get and set methods can be accessed via the applets property of the JavaScript document object. The applets property is actually an array (beginning with zero) containing references to all applets contained in a page.

7.9.1 JavaScript for accessing the token


The next snippet of JavaScript shows how our class may be accessed.
<SCRIPT LANGUAGE="JavaScript"> var username; var token; var serverName; 3. function loadValues() { 4. var app = document.applets[0]; 5. if (app == null) { username = ""; token = ""; serverName = ""; } else { 6. username = app.getUsername(); 7. token = app.getToken(); 8. serverName = app.getServerName(); } } 9. function showApplet() { 10. loadValues(); 11. alert("User:" + username + "\nToken:" + token + "\nServer:" + serverName); } </SCRIPT> 1. 2.

Explanation of numbered lines: 1. A script block is declared for inclusion in an HTML page. Our script will be placed in the HTML head section.

Chapter 7. Customized chat UI applet

189

2. The variables are declared for accessing the class field values. 3. The loadValues function accesses the applet field values via the appropriate get methods. 4. Our applet is accessed; it is the first applet on the page. 5. The variables are populated with empty values if the applet was not found. 6. The username variable is populated via the applet getUsername method. 7. The token variable is populated via the applet getToken method. 8. The serverName variable is populated via the applet getServerName method. 9. The showApplet method tests our loadValues method by displaying the variable values in a popup window. 10.The loadValues function is called. 11.The variable values are displayed in a popup window. The JavaScript may be utilized with a button on a page. The following HTML accomplishes the feat.

7.9.2 The HTML form


Our HTML includes a form containing one button. The button onClick event signals what occurs upon button selection. Our showApplet function is called when this button is selected.
<FORM> <INPUT NAME="Applet" VALUE="Applet Properties" TYPE="Button" onClick="showApplet();"> </FORM>

Now, the complete HTML for our page is displayed. It includes the JavaScript functions and our applet. One important note is the inclusion of the MAYSCRIPT option (highlighted) in the applet declaration. This makes the applet available to JavaScript.
<HTML> <HEAD> <TITLE>CustomizeChatUI</TITLE> <SCRIPT LANGUAGE="JavaScript"> var username; var token; var serverName;

190

Working with the Sametime Client Toolkits

function loadValues() { var app = document.applets[0]; if (app == null) { username = ""; token = ""; serverName = ""; } else { username = app.getUsername(); token = app.getToken(); serverName = app.getServerName(); } } function showApplet() { loadValues(); alert("User: " + username + "\nToken: " + token + "\nServer: " + serverName); } </SCRIPT> </HEAD> <BODY> <APPLET CODE="CustomizeChatUI.class" WIDTH="350" HEIGHT="200" NAME="CustomizeChatUI" MAYSCRIPT> <param name="archive" value="export.jar, STComm.jar, CommRes.jar"> <param name="loginName" value="ctester"> <param name="password" value="password"> </APPLET> <FORM> <INPUT NAME="Applet" VALUE="Applet Properties" TYPE="Button" onClick="showApplet();"> </FORM> </BODY> </HTML>

The next two figures show the results of first loading the applet (with button) and the selection of the button.

Chapter 7. Customized chat UI applet

191

Figure 7-14 Applet loaded with JavaScript

Figure 7-15 Window displayed upon button selection

7.9.3 Sharing information with other applets


Our code is nice, but it becomes useful when the token may be passed to another applet. The token may be used to log into the Sametime server, thus bypassing the need for the user to retype their username and password. It streamlines the user experience. Our code will be used to pass the token information to another applet. The applet used for this demonstration is the sample awareness applet included with the Java Toolkit. The sample code must be slightly altered to log in by token rather than username/password. In addition, the awareness applet HTML must include applet parameters for token and server as well as login name. The code change occurs in the login method. The loginByPassword call is replaced with a call to loginByToken.

192

Working with the Sametime Client Toolkits

private void login() { m_comm = (CommunityService) m_session.getCompApi(CommunityService.COMP_NAME); m_comm.addLoginListener(this); m_comm.loginByToken( getParameter("serverName") , getParameter("loginName") , getParameter("password") ); }

Note: In this example we want to test login by token, so we simply replace the login method. In production you may want your applet to be more flexible: to allow login both by id/password and by token. If you look at our source code from Chapter 6, A place-based auction example on page 101 you can see an example that allows both ways of login (and in addition opens a login dialog if no login parameters are passed along).

Our sample HTML is altered as well. A new JavaScript function is added to load the sample awareness applet. The function is listed next.
function loadAwareness() { 1. loadValues(); 2. document.writeln("<HTML>"); document.writeln("<HEAD>"); document.write("<TITLE> "); document.write("Toolkit Sample Awareness Applet"); document.writeln("</TITLE>"); document.writeln("</HEAD>"); document.writeln("<BODY BGCOLOR=\"C0C0C0\">"); 3. document.write("<APPLET CODE=AwarenessApplet.class ); document.write("ARCHIVE=\aware.jar\); document.write(" WIDTH=\250\ ); document.writeln(" HEIGHT=\300\>"); document.write("<param name=\"archive\" ); document.writeln("value=\"aware.jar,CommRes.jar,STComm.jar\">"); 4. document.writeln("<param name=\"loginName\" value=\"" + username + "\">"); 5. document.writeln("<param name=\"password\" value=\"" + token + "\">"); 6. document.writeln("<param name=\"serverName\" value=\"" + serverName + "\">"); document.writeln("</APPLET>"); document.writeln("</BODY>"); document.writeln("</HTML>"); }

Chapter 7. Customized chat UI applet

193

Explanation of numbered lines: 1. The loadValues method is called to populate the required variables. 2. The writeln method of the JavaScript document object writes the specified text to the browser window. The written material overwrites the current browser content. 3. The HTML is displayed for the awareness applet. 4. The loginName parameter is written with the username variable as the value. 5. The password parameter is written with the token variable as the value. 6. The serverName parameter is written with the serverName variable. The loadAwareness applet loads the specified HTML in the currently open browser window. Another button is added to our page for calling our new function.
<INPUT NAME="Applet" VALUE="Awareness" TYPE="Button" onClick="loadAwareness();">

The new button and JavaScript function are added to our HTML file. The results are displayed in the next two figures.

Figure 7-16 New button for loading another applet

194

Working with the Sametime Client Toolkits

If you click on the button labelled Awareness in Figure 7-16, the applet shown in Figure 7-17 will be launched and login will be performed by token.

Figure 7-17 Applet launched by other applet using token for login

One applet was launched, accepting the login information submitted from another applet. Applet-to-applet communication is critical to a smooth user experience. We do not want our user community repeatedly entering authentication information. They will become annoyed and it may lead to an application not being used.

Chapter 7. Customized chat UI applet

195

Note: Passing token between applets may not be the best approach, but it is an easy way to let separate applets work in a concerted manne, as you can see. If you are designing a complex Sametime application (versus using different existing components) you should consider having one component on the client handle the authentication and then let the other Sametime components get their login information from the authentication component. Yet another approach is to handle it on the server side, possibly together with single sign-on to other systems like e-commerce, CRM, and so on. To learn more about what you can do on the server side see the redbook Working with the Sametime Community Server Toolkit, SG24-6667.

7.10 Summary
In this chapter we have focused on the ability to create your own customized chat window with the Sametime Java toolkit. During our work with the sample we have also shown you how to use the storage and token services in Sametime. In addition we have walked through how a Sametime applet can be deployed via a Lotus Domino database.

196

Working with the Sametime Client Toolkits

Part 3

Part

C++ toolkit

Copyright IBM Corp. 2002. All rights reserved.

197

198

Working with the Sametime Client Toolkits

Chapter 8.

Working with the C++ toolkit


In this chapter we provide an overview of the Sametime C++ community client toolkit and describe how you can get started with it. We also give you some pointers to additional information about the C++ toolkit when appropriate.

Copyright IBM Corp. 2002. All rights reserved.

199

8.1 Overview
The Sametime 3.0 C++ Toolkit is a collection of static library components that allow developers to enhance Windows applications with Community Services, such as awareness and instant messaging. It is based on the same toolkit architecture as the Sametime 3.0 Java Toolkit. However, the C++ toolkit supports only the Community Services (that means no Meeting Services), and does not provide any UI components. It is geared towards allowing developers to quickly and easily Sametime-enable any Win32- or MFC-based Windows application. Although applications developed with this toolkit will work when run against a Sametime 1.5 server, any toolkit services that require features new to Sametime 3.0 (that is, Storage and Place services), will not function when a Sametime 3.0 server is not available. The C++ Toolkit uses only Standard Type Library (STL) containers and is therefore standard-based. The C++ Toolkit is not based on Microsoft Foundation Classes (MFC) or Object Linking and Embedding (OLE) technologies. If needed, these technologies can be used as a second layer on top of the toolkit. The toolkit has a layered architecture with two different layers: The Transport Layer The layer through which all communication with the Sametime server passes. The Service Layer The layer providing access to the Sametime Community Services.

200

Working with the Sametime Client Toolkits

Figure 8-1 Sametime Server

The toolkit is modular, thread-safe, and extendable, providing an object-oriented API, which exposes the entire set of Community Services features provided by Sametime 3.x. The Sametime 3.0 C++ Toolkit supports the Microsoft Visual C++ 6.0 Developer Studio SP5.

8.1.1 Modular
The Sametime 3.0 C++ Toolkit is component-based, and the different services it provides are divided among many components. Each component is a separate static library. The developer links into the final project only the binary libraries of the components needed.

8.1.2 Thread-safe
The Sametime 3.0 C++ Toolkit is thread-safe so that a Sametime-enabled application built on top of the Toolkit can have many threads. Calls to the Toolkit API can come from different threads; the Toolkit handles multiple threads without requiring additional work by the developer.

Chapter 8. Working with the C++ toolkit

201

8.1.3 Extendable
In the Sametime 3.0 C++ Toolkit, developers can add components that provide new services and a new User Interface (UI), making the Toolkit expandable by both core Sametime developers and by third-party developers. This chapter does not describe how to write such components. However, future documentation will include this information.

8.1.4 Object-oriented API


The Sametime 3.0 C++ Toolkit provides a natural object-oriented API for the C++ developer. Each service is implemented by a component class. Many services create and require use of one or more additional helper objects in order to execute the service functionality.

8.1.5 The toolkit services


This section describes the services provided by the Sametime 3.0 C++ Toolkit.

Community services
Table 8-1 lists and describes the community services available in the Sametime 3.0 C++ Toolkit.
Table 8-1 Community services
Name of service Community service Description A required component in almost any use of the Toolkit. It allows you to log in, log out, and make changes to online status, online attributes, and privacy settings. Provides notifications of changes in the online status and attributes of users in the community. This service is sometimes referred to as People Awareness. Provides one-to-one communication between clients. It is used mostly for Instant Messaging chat between users, but it can also be used to exchange any kind of text or binary data. Provides the ability to create virtual meeting places that users can enter or leave, see who is in the meeting place, and share activities. This service is sometimes referred to as Place-Based Awareness, and it is a major cornerstone of the Sametime 3.0 architecture.

Awareness service

Instant messaging service

Places service

202

Working with the Sametime Client Toolkits

Name of service Storage service

Description Provides server-side storage of user-related data. A user can access his personal data from any Sametime-enabled application. For example, Sametime Connect uses this service to store a users Buddy List on the Sametime server so the user can access it regardless of where he logs in. Provides name resolving and group content lookup. Provides directory-browsing services. Allows posting a message to many users at once. Allows generation of temporary login tokens.

Lookup service Directory service Post service Token service

8.2 Getting started


To get started with C++ programming for Sametime you need to get the Sametime C++ toolkit and unpack it on your development machine.

8.2.1 The toolkit package


To access the Toolkit pages that include the Toolkit documentation, samples, and binaries, follow these steps: 1. Navigate to the home page of your Sametime 3.x server (http://<your_sametime_server_name). 2. Click the Toolkit link at the bottom of the page. You might need to scroll down the page to see the link. 3. Click C++ Toolkit on the Toolkits page. You are now at the Sametime 3.0 C++ Toolkit home page, as shown in Figure 8-2 on page 204.

Chapter 8. Working with the C++ toolkit

203

Figure 8-2 The Sametime 3.0 C++ Toolkit home page

The Sametime 3.0 C++ toolkit is provided as an installable package. Table 8-2 describes the installed directory structure.

204

Working with the Sametime Client Toolkits

Table 8-2 Toolkit directory structure


Name of subfolder doc inc lib Description The C++ Toolkit HTML Reference Manual. The C++ Toolkit header files. The C++ Toolkit static libraries, including both the components implementing the different services and additional core libraries required for any Sametime-enabled application. The libraries are provided both in release and debug binary versions. The C++ Toolkit Sample files, including all the sources of the tutorial samples.

samples

Note: The samples provided with the C++ toolkit assume the required include files are stored in directories under the inc directory. However, the zip file with toolkit binaries that we downloaded from the Sametime server had the directory structure reversed (so that those directories that should be under the inc directory were top level directories and each of them had a sub directory called inc. Thus you may have to re-arrange your directory structure if this also happens to you.

Note: Another thing we encountered when trying to compile our first sample program was a missing lib file from the toolkit binaries. Even though the file has not been included in the toolkit zip file (as it should be), it still is on the Sametime server. If you also encounter this problem simply search for the file on the Sametime server.

8.2.2 Background information


The Sametime 3.0 C++ Toolkit is described in more detail in the Tutorial and Developer Guide that is available with the toolkit as a PDF file. This redbook provides advanced samples that are based on the samples in the Tutorial. You can see a description of these samples in Table 8-3 on page 206.

Chapter 8. Working with the C++ toolkit

205

Table 8-3 Additional samples


Name of sample Meetings Sample Description Provides an example of how to create sametime meetings, including N-way chat, using the Places, Post, and Token Services of the C++ Toolkit. Provides an example of how to create a Win32 console or simple Win32 application without using MFC libraries.

Win32Status Sample

You can also download a PDF file with a poster of the Sametime community services C++ object model from the C++ toolkit section on the Sametime server.

8.3 Summary
In this chapter we introduced you to the Sametime C++ community toolkit. We described how you get the toolkit, and pointed you to additional samples and information provided with the toolkit.

206

Working with the Sametime Client Toolkits

Chapter 9.

A complex meetings sample


This chapter provides a detailed description of the creation of a complex Sametime Meetings applications using the C++ 3.0 toolkit. It shows how to take advantage of the Sametime Meeting services on the Sametime server using the Places, Post, and Token services on the client. We also show you how to launch the Sametime Meeting client, which is Java-based, by a URL from our C++ program. We start by giving you an overview of how the final program looks before we introduce you to the object model of our sample application. We introduce you to the major classes in the application. We describe each of these in detail and discuss how we initialize the main MeetingUI class and how its API can be used. Once you have a good feel for the objects involved, we describe the flow in the application from the user that invites to a meeting and the user that is invited. We have split this flow up into four topics or steps: The invitation (creating/accepting) The place (creating/joining) Generating a token Launching the Sametime Java Meeting client This sample highly leverages the Sametime places architecture, as you will see during our discussion of the four steps.

Copyright IBM Corp. 2002. All rights reserved.

207

The source code for the full application is available from the IBM Redbooks Web site. See Appendix E, Additional Web material on page 407 for instruction on how to get the material.

9.1 Overview
As a foundation, we will use the BasicBuddyList sample from the Tutorial for the C++ toolkit. The BasicBuddyList provides a simple awareness-based instant messaging application. You may want to read or at least browse the description of the BasicBuddyList in the C++ toolkit tutorial since we are assuming familiarity with that sample. In this chapter we show how to extend the BasicBuddyList sample to create more complex Chat, Audio Video, Application Sharing and WhiteBoard Meeting applications using the C++ 2.0 Toolkit. We show you how to create full Sametime meetings, starting from a Chat Meeting, and advancing to more complex meetings like Audio and Video meetings using the Post, Places and Token services. Figure 9-1 shows the Meetings sample main dialog, where you can just add users, right-click on one or more of them, and select the meeting to which you want to invite the user or the users.

Figure 9-1 Meetings sample main dialog

208

Working with the Sametime Client Toolkits

Figure 9-2 shows the Invitation dialog, where you prepare your invitation and send it to all users you have selected.

Figure 9-2 The Invitation dialog

Figure 9-3 on page 210 shows the chat meeting (also called N-Way chat) dialog, where we can send and receive chats among several participants.

Chapter 9. A complex meetings sample

209

Figure 9-3 The N-Way chat dialog

Now you can even upgrade your meeting to a video meeting, for example, by adding tools, as shown in Figure 9-4.

Figure 9-4 The Add Tools dialog

210

Working with the Sametime Client Toolkits

As you can see in Figure 9-5, once the tools are added, an Audio - Video meeting will be launched.

Figure 9-5 The Audio Video meeting

Chapter 9. A complex meetings sample

211

9.2 Sample architecture


Figure 9-6 shows the architecture of the additional classes required to extend the BasicBuddyList sample. It shows the relationships among the classes. We will first describe these classes in detail, and then look at the flow in the code to create a meeting with more than two participants.

Listener

Meetings Sample Architecture

Meetings class Service class

MyMeetingUIPlacesServiceListener

MeetingDlg

MyMeetingUITokenServiceListener

MeetingUI InviteUIDlg

MyPostServiceListener

Place

Places Service

Token Service

Post Service

Post

MyPlaceListener

MyMeetingControllerTokenServiceListener

MeetingController MyUserInPlaceListener

MyMeetingControllerPlacesServiceListener MeetingLauncher NWayChatUIDlg MyMyselfInPlaceListener

MySectionListener

Figure 9-6 Sample architecture

212

Working with the Sametime Client Toolkits

9.2.1 The MeetingUI class


The MeetingUI class will give our application the ability to create Instant Meetings, with one or more of the tools: Chat, Audio, Video, Application Sharing and White Board. This class will also provide the ability to launch the Sametime Help to provide you with additional information about the Audio/Video feature, and to launch the Audio/Video Wizard, that allows you to ensure that Audio/Video will function properly during your online meeting. Figure 9-7 focuses on the MeetingUI part of the previous architecture diagram (see Figure 9-6). It shows which other service and listener classes it uses, and the relationships among them and the sample classes, MeetingDlg and InviteUIDlg. The MeetingDlg and InviteUIDlg will be described in detail later in this chapter.

MyMeetingUIPlacesServiceListener

MeetingDlg

MyMeetingUITokenServiceListener

MeetingUI InviteUIDlg

MyPostServiceListener

Place

Places Token Service Service

Post Service

Post

Figure 9-7 MeetingUI class diagram

Construction and destruction


The MeetingUI class will be created and initialized with a single call to a static function, Instance, so it will have only one instance in memory and will hold a reference count to itself. It will destroy itself when the number of the reference count decreases to 0 . In addition, the MeetingUI class will accept invitations to meetings from other clients. We created an instance at the time we logged in, so it will be able to receive the invitations at any given moment.

Chapter 9. A complex meetings sample

213

Sametime meeting types


The MeetingUI class will define all the Sametime meeting types. Each class in the sample that wants to create a meeting will use the required type defined in MeetingUI. For a list of Sametime meeting types, see Table 9-1.
Table 9-1 Sametime meeting types
Sametime meeting type ST_MEETING_TYPE_ERROR ST_CHAT_MEETING ST_AUDIO_MEETING ST_VIDEO_MEETING ST_COLLABORATION_MEETING ST_SHARE_MEETING ST_AV_WIZARD_MEETING ST_HELP ID -1 0 1 2 3 4 5 6 Description Meeting type error Chat meeting Audio meeting Video meeting Collaboration meeting Application Sharing meeting Launch the Audio/Video wizard Launch Sametime help

General services
The MeetingUI class will expose the following methods to other classes for creating meetings, opening A/V help and opening the A/V wizard as you can see in Table 9-2.
Table 9-2 MeetingUI General Services
Methods void CreateMeeting(list<STWatchedUser*> lstUsers,long meetingType) void OpenAVHelp() void OpenAVWizard() bool IsMeetingsServiceAvailable() Description Creates Sametime meeting with the specific list of users and the specific meeting type (see Table 9-1). Opens the Sametime Audio/Video Help. Launches the Audio/Video Wizard. Returns true/false if the Place Service is available, so meeting can be created.

214

Working with the Sametime Client Toolkits

MeetingUI.h
The MeetingUI.h file is shown in Example 9-1.
Example 9-1 MeetingUI.h
#if !defined __MEETING_UI__ #define __MEETING_UI__ #pragma warning (disable: 4786) #include <list> #include <string> class class class class class class class class class class class class class STSession; PostService; PlacesService; TokenService; MyPostServiceListener; MyMeetingUIPlacesServiceListener; MyMeetingUITokenServiceListener; PostEvent; PlacesServiceEvent; TokenEvent; STWatchedUser; STUser; Post; ST_MEETING_TYPE_ERROR -1 ST_CHAT_MEETING0 ST_AUDIO_MEETING 1 ST_VIDEO_MEETING2 ST_COLLABORATION_MEETING3 ST_SHARE_MEETING4 ST_AV_WIZARD_MEETING 5 ST_HELP 6 CHAT_ACTIVITY AUDIO_ACTIVITY VIDEO_ACTIVITY APPSHARE_ACTIVITY WHITEBORD_ACTIVITY 1 2 4 8 16

#define #define #define #define #define #define #define #define #define #define #define #define #define

#define SAMETIME_MEETING_SERVER_PORT 8081 ////////////////////////// // MeetingUI - Sametime-enabled Chat/Audio/Video/Share/Collaborate Meetings using namespace std; class MeetingUI { friend class InviteUIDlg;

Chapter 9. A complex meetings sample

215

public: //Instace static MeetingUI* Instance(STSession* pSTSession = NULL); //Destruction void Destroy(); virtual ~MeetingUI(); // Api void CreateMeeting(list<STWatchedUser*> lstUsers ,long meetingType); void OpenAVHelp(); void OpenAVWizard(); bool IsMeetingsServiceAvailable(); //Services static CString FormatUrlCharacters(const CString &strInput); static long GetMeetingTypeFromActivities(long lActivities); static void OpenMRC(long lMeetingType, CString strUrl); wstring GetMyUserId(); CString GetServerName();

// Callback events from Post Service Listener void Posted(PostEvent); // Callback events from Places Service Listener void OnPlacesServiceAvailable(PlacesServiceEvent event); void OnPlacesServiceUnavailable(PlacesServiceEvent event); // Callback events from Token Service Listener void OnTokenGenerated(TokenEvent event); void OnGenerateTokenFailed(TokenEvent event); protected: //Calls from friend class InviteUIDlg void OnSend(Post* pPost, long lActivities, bool b1On1); void OnJoin(Post* pPost); void OnRespond(Post* pPost); private: //Private Constructor MeetingUI(STSession* pSTSession); //Private Methods CString GetMyUserName(); wstring GetUniquePlaceName(); void ArrangeActiveStatusOnly(list<STWatchedUser*>& lstUsers); static long GetRegKey(HKEY hKeyBase, LPCTSTR lpSubKey, LPTSTR lpszRetData);

216

Working with the Sametime Client Toolkits

CString GetAVWizardUrl(CString token); //Private members static MeetingUI* _Instance; static int m_refCount; STSession* m_pSTSession; PostService* m_pPostService; PlacesService* m_pPlacesService; TokenService* m_pTokenService; MyPostServiceListener* m_pMyPostServiceListener; MyMeetingUIPlacesServiceListener* m_pMyPlacesServiceListener; MyMeetingUITokenServiceListener* m_pMyTokenServiceListener; bool m_bServiceAvailable; }; #endif //__MEETING_UI__

9.2.2 The MeetingController class


The MeetingController class is a base class, which was designed to be inherited by the NWayChatUIDlg class and the MeetingLauncher class. This class will hold handles for the Places and Token Services and will handle most of the events fired from these classes. This class will also handle all the necessary code to launch meetings, like preparing the Meeting room client (MRC) and preparing the URL.

Place

Places Service

Token Service

Post Service

Post

MyPlaceListener

MyMeetingControllerTokenServiceListener

MeetingController

MyMeetingControllerPlacesServiceListener MeetingLauncher NWayChatUIDlg

Figure 9-8 MeetingController class diagram

Chapter 9. A complex meetings sample

217

Construction and destruction


We use a single constructor to construct and initialize the MeetingController class. The constructor will accept the following parameters: Session The current session of the application, it will help us to get the Token and Places Services so we can use them. Place The specific place we want to use for our meeting, this place will be copied in this constructor. Activities A long type which represents all the activities which we want to add to the Place. Meeting Type A long type which represents the type of the meeting we want for the Place, this helps us to know what size of meeting dialog to open. Initiator A boolean type which will be true if we are the initiators of the meetings, false if we join the meeting. In the destructor we remove and delete all the listeners.

Event handling
This class receives events from the Places Service listener, Place listener and the Token listener. In some cases the MeetingController class will handle these events by itself, in other cases they will be handled by the derived class, or even by both base and derived classes. For more detailed event handling, refer to Table 9-3.
Table 9-3 MeetingController event handling
The event OnTokenGenerated OnGenerateTokenFailed OnEntered OnLeft OnSectionAdded OnActivityRemoved OnActivityAdded OnEnterFailed OnAddActivityFailed NWayChatUIDlg, MeetingController MeetingController, MeetingLauncher MeetingController, MeetingLauncher The class/classes who handle the event MeetingController, MeetingLauncher MeetingController, MeetingLauncher NWayChatUIDlg, MeetingLauncher NWayChatUIDlg, MeetingLauncher NWayChatUIDlg

218

Working with the Sametime Client Toolkits

The event OnAttributeChanged OnPlacesServiceAvailable OnPlacesServiceUnavailable

The class/classes who handle the event MeetingController NWayChatUIDlg, MeetingController NWayChatUIDlg, MeetingController

MeetingController.h
The MeetingController.h file is shown in Example 9-2.
Example 9-2 MeetingController.h
#if !defined __MEETING_CONTROLLER__ #define __MEETING_CONTROLLER__ #define #define #define #define #define CHAT_MRC_MEETING_ACTIVITY VIDEO_MRC_MEETING_ACTIVITY AUDIO_MRC_MEETING_ACTIVITY APPSHARE_MRC_MEETING_ACTIVITY WHITEBORD_MRC_MEETING_ACTIVITY 0x9106 0x9104 0x9103 0x9102 0x9101

#include "PlaceEvent.h" class class class class class class class class class class Place; TokenService; PlacesService; TokenEvent; PlacesServiceEvent; PlaceMemberEvent; MyPlaceListener; MyMeetingControllerTokenServiceListener; MyMeetingControllerPlacesServiceListener; STSession;

class MeetingController { public: //Constructors MeetingController(STSession* pSTSession, const Place& place, long lActivities, long lMeetingType, bool bInitiator = true);

//Destructor virtual ~MeetingController(); //Callback events from Token Service Listener virtual void OnTokenGenerated(TokenEvent event);

Chapter 9. A complex meetings sample

219

virtual void OnGenerateTokenFailed(TokenEvent event); //Callback events from Place Listener virtual void OnEntered(PlaceEvent event){}; virtual void OnLeft(PlaceEvent event){}; virtual void OnSectionAdded(PlaceEvent event){}; virtual void OnActivityRemoved(PlaceEvent event){}; virtual void OnActivityAdded(PlaceEvent event); virtual void OnEnterFailed(PlaceEvent event); virtual void OnAddActivityFailed(PlaceEvent event); virtual void OnAttributeChanged(PlaceMemberEvent event); //Callback events from Place Service Listener virtual void OnPlacesServiceAvailable(PlacesServiceEvent event); virtual void OnPlacesServiceUnavailable(PlacesServiceEvent event); protected: //Protected methods void AddMRCActivitiesToPlace(); //Protected Members Place* m_pPlace; long m_lActivities; long m_lMeetingType; bool m_bInitiator; void PrepareTheMRC(); bool m_bActivityAdded; private: //Private Methods CString GetFormattedActivities(); void SetActivitiesFromFormattedString(CString strActivities); CString PrepareMRCUrl(CString token); //Private Members TokenService* m_pTokenService; PlacesService* m_pPlacesService; MyPlaceListener* m_pPlaceListener; MyMeetingControllerTokenServiceListener* m_pTokenServiceListener; MyMeetingControllerPlacesServiceListener* m_pPlaceServiceListener; }; #endif //__MEETING_CONTROLLER__

220

Working with the Sametime Client Toolkits

9.2.3 The NWayChatUIDlg class


The NWayCharUIDlg class is responsible for handling chat meetings. Figure 9-9 shows which listeners the class uses and how it relates to the MeetingController and the CDialog classes.

MeetingController

CDialog MyUserInPlaceListener

NWayChatUIDlg

MyMyselfInPlaceListener

MySectionListener

Figure 9-9 NWayChatUIDlg class diagram

Figure 9-10 on page 222 shows how the dialog appears and explains the different elements on the screen.

Chapter 9. A complex meetings sample

221

This Meeting menu provides more functions to the meeting like Add Tools.

Transcript window which shows all the messages sent on the meeting.

This icon identify the user who is currently typing.

The meeting participant list shows all the users Who are currently in the meeting And their status.

This pane identify the incoming and outgoing of users from the meeting

Click here to send the message to the other users.

Click here to leave the meeting and close the dialog.

Figure 9-10 The NWayChat dialog

The NWayChatUIDlg is a multi-user chat dialog. Unlike the ChatUIDlg, in which we can only talk to one person at a time, this new chat dialog gives us the ability to create a multiple-user chat room using the Places architecture, so if we send a message to the chat room everybody in the chat room will get the message and will be able to respond to it the same way. The NWayChatUIDlg can be upgraded to other meetings, like Audio, Video, Application sharing, and White board meetings by adding activities to the place. We use the AddToolsDlg to get the tools/activities that we want to add to the meeting, as shown in Figure 9-11 on page 223.

222

Working with the Sametime Client Toolkits

Figure 9-11 The Add Tools dialog

This class will use multiple inheritance, in which it will inherit both from the MeetingController and CDialog classes. Therefore, it can get all the Place and PlacesService events, will have the ability to upgrade to other meetings using the MeetingController class, and will get all the functionality of a dialog from the CDialog class. Refer to Figure 9-8 and Figure 9-9 for class diagrams. The NWayChatUIDlg will have a participant list to show who is in the chat room and the status of each participant. It will have a text box in which we can send messages to the chat room and a transcript window which records all the messages sent to the chat room. This is shown in Figure 9-10 on page 222.

Construction and destruction


We use a single constructor to construct and initialize the MeetingController class. The constructor will accept the following parameters: Session The current session of the application, it will be passed to the MeetingController base class in the initialization list. Place The specific place we want to use for our meeting, it will be passed to the MeetingController base class in the initialization list and will be used later by this class to enter sections. Initiator A boolean type which will be passed also to the MeetingController base class, this member will also be used by this class to indicate if we are the meeting initiators. Refer to Construction and destruction on page 218 for more details about the MeetingController base class construction. In the destructor we will remove and delete all the listeners.

Chapter 9. A complex meetings sample

223

Event handling
The NWayChatUIDlg class will handle all the basic events which are described in Table 9-3 on page 218. In addition, it will handle the enter/leave events of users to/from the chat room, along with enabling the sending and receipt of messages. For a full list of events handled by NWayChatUIDlg refer to Table 9-4.
Table 9-4 NWayChatUIDlg event handling
Handled by NWayChatUIDlg MeetingController NWayChatUIDlg MeetingController NWayChatUIDlg NWayChatUIDlg NWayChatUIDlg NWayChatUIDlg MeetingController NWayChatUIDlg NWayChatUIDlg NWayChatUIDlg NWayChatUIDlg NWayChatUIDlg The event OnPlacesServiceAvailable OnPlacesServiceUnavailable OnEntered OnLeft OnSectionAdded OnActivityAdded OnUsersEntered OnUserLeft OnTextReceived OnPlaceMemberAttributeChanged OnPlaceMemberAttributeRemoved Description Indicates when the Places Service is available. Indicates when the Places Service is not available. Indicates that we just entered the place. Indicates that we just left the place. A section has been added to the place. An activity has been added to the place. A user has just entered the section. A user has just left the section. Indicates that I have just received a text message. An attribute of a user has been changed. An attribute of a user was removed.

224

Working with the Sametime Client Toolkits

NWayChatUIDlg.h
The NWayChatUIDlg.h file is shown in Example 9-3.
Example 9-3 NWayChatUIDlg
#if !defined __NWAY_CHATUI_DLG__ #define __NWAY_CHATUI_DLG__ #pragma warning (disable : 4786) #include "resource.h" #include "MeetingController.h" #include <list> class class class class class class class STSsession; MySectionListener; MyselfInPlace; MyMyselfInPlaceListener; AwarenessList; MyUserInPlaceListener; AddToolsDlg;

class NWayChatUIDlg : public CDialog, public MeetingController { friend class AddToolsDlg; public: //Constructors NWayChatUIDlg(STSession* pSTSession, const Place& place, CString strMyName, bool bInitiator = true); //Destructor ~NWayChatUIDlg(); // Enums enum {IDD = IDD_NWAY_CHAT_DLG }; // Overrides MeetingController //PlacesService void OnPlacesServiceAvailable(PlacesServiceEvent event); void OnPlacesServiceUnavailable(PlacesServiceEvent event); //Place void OnEntered(PlaceEvent event); void OnLeft(PlaceEvent event); void OnSectionAdded(PlaceEvent event); void OnActivityAdded(PlaceEvent event); // Callback events from Section Listener

Chapter 9. A complex meetings sample

225

void OnUsersEntered(SectionEvent event); void OnUserLeft(SectionEvent event); // Callback events from MyselfInPlace Listener void OnTextReceived(MyselfEvent event); //Callback events from UserInPlace Listener void OnPlaceMemberAttributeChanged(PlaceMemberEvent event); void OnPlaceMemberAttributeRemoved(PlaceMemberEvent event); protected: //Callback events from AddToolsDlg void OnSendTools(long lActivities); void OnAddToolsDlgRequestClose(); // Overrides virtual void OnCancel(); virtual BOOL OnInitDialog(); virtual void DoDataExchange(CDataExchange* pDX); // Messages afx_msg void OnLeave(); afx_msg void OnSend(); afx_msg void OnChangeEditMessage(); afx_msg void OnAddTools(); afx_msg void OnClose(); DECLARE_MESSAGE_MAP() private: //Private members Section* m_pSection; MyselfInPlace* m_pMyselfInPlace; MySectionListener* m_pMySectionListener; MyMyselfInPlaceListener* m_pMyMyselfInPlaceListener; AwarenessList* m_pParticipantList; CString m_strTransScript; CString m_strMyName; CString m_strMessage; list<UserInPlace*> m_lstUsersInPlace; MyUserInPlaceListener* m_pMyUserInPlaceListener; AddToolsDlg* m_pAddToolsDlg; }; #endif //__NWAY_CHATUI_DLG__

226

Working with the Sametime Client Toolkits

AddToolsDlg.h
The AddToolsDlg.h file is shown in Example 9-4.
Example 9-4 AddToolsDlg.h
if !defined __ADD_TOOLS_DLG__ #define __ADD_TOOLS_DLG__ #include "resource.h" class NWayChatUIDlg; ////////////////////////// // AddToolsDlg class AddToolsDlg : public CDialog { public: //Constructor AddToolsDlg(NWayChatUIDlg* pCallBack, long lInitialActivities); // Destructor virtual ~AddToolsDlg(); // Enums enum { IDD = IDD_ADD_TOOLS}; protected: // Overrides virtual BOOL OnInitDialog(); virtual void OnCancel(); // Messages afx_msg void OnSend(); afx_msg void OnClose(); DECLARE_MESSAGE_MAP() private: // Private members NWayChatUIDlg* m_pCallBack; long m_lActivities; }; #endif // __ADD_TOOLS_DLG__

Chapter 9. A complex meetings sample

227

9.2.4 The MeetingLauncher class


The MeetingLauncher class is designed to handle all instant meetings except for the chat meeting. This class inherits from the base class MeetingController. The MeetingController class in this case will do most of the work.

Construction and destruction


We use a single constructor to construct and initialize the MeetingController class. The constructor will accept the following parameters: Session The current session of the application, it will be passed to the MeetingController base class in the initialization list. Place The specific place we want to use for our meeting, it will be passed to the MeetingController base class in the initialization list. Activities A long type which represents all the activities which we want to add to the Place. It will be passed to the MeetingController base class in the initialization list. Meeting Type A long type which will represent the type of the meeting we want for the Place. It will be passed to the MeetingController base class in the initialization list. Initiator A boolean type which will be passed also to the MeetingController base class.

Event handling
The MeetingLauncher class will handle most of the MeetingController base class events. In some cases the MeetingLauncher will be the only class to handle the event and in other cases the MeetingLauncher will handle the event and pass it to the MeetingController to handle the event, too. For a general overview of MeetingController event handling, refer to Table 9-3 on page 218. For detailed event handling of the MeetingLauncher class, refer to Table 9-5.
Table 9-5 MeetingLauncher event handling
Handled by 1.MeetingLauncher 1.MeetingController 2.MeetingLauncher 1.MeetingController 2.MeetingLauncher The event OnEntered OnEnterFailed OnAddActivityFailed Description We just entered the place. We left the place. We have failed to add a new activity.

228

Working with the Sametime Client Toolkits

Handled by 1.MeetingLauncher 1.MeetingController 2.MeetingLauncher 1.MeetingController 2.MeetingLauncher

The event OnLeft OnTokenGenerated OnGenerateTokenFailed

Description We left the place. A token has been generated for us. Generating the token failed.

MeetingLauncher.h
The MeetingLauncher.h file is shown in Example 9-1 on page 215
Example 9-5 MeetingLauncher.h
#if !defined __MEETING_LAUNCHER__ #define __MEETING_LAUNCHER__ #pragma warning (disable:4786) #include "resource.h" #include "MeetingController.h" class MeetingLauncher : public MeetingController { public: //Constructors MeetingLauncher(STSession* pSTSession, const Place& place, long lActivities, long lMeetingType, bool bInitiator = true); //Destructor ~MeetingLauncher(); // Overrides MeetingController //Place void OnEntered(PlaceEvent event); void OnEnterFailed(PlaceEvent event); void OnAddActivityFailed(PlaceEvent event); void OnLeft(PlaceEvent event); //Token Service void OnTokenGenerated(TokenEvent event); void OnGenerateTokenFailed(TokenEvent event); }; #endif //__MEETING_LAUNCHER__

Chapter 9. A complex meetings sample

229

9.2.5 The InviteUIDlg class


The InviteUIDlg class is actually our invitation dialog; this class will handle both incoming and outgoing invitations. Figure 9-12 shows how it relates to the CDialog class and the Post service.

CDialog

Post

InviteUIDlg

Figure 9-12 InviteUIDlg class diagram

The incoming invitation


Figure 9-13 shows how an incoming invitation is presented.

The invitation type. The invitation topic and message

Icon which identify the type of the meeting

Click here to accept the invitation and join the meeting.

Click here to if you want to respond to the invitation this will open Im to the user who sent the Invitation.

Click here to decline the invitation and close the dialog.

Figure 9-13 The incoming invitation

For the incoming invitation we will have a dialog box which contains the topic of the invitation and the message itself. The dialog will also have an icon which identifies the meeting type (Chat, Audio, Video, Application Sharing, Collaborate), and 3 more buttons: Join, Respond and Close. Table 9-6 on page 231 describes the buttons in detail.

230

Working with the Sametime Client Toolkits

Table 9-6 Incoming invitation button descriptions


Button Join Respond Close Description Press this button to join the meeting. Press this button to respond to the invitation. This will open an IM to the user who placed the invitation. Press this button to close the invitation without joining or responding to the invitation.

The outgoing invitation


Figure 9-14 shows how the user sets up an outgoing invitation.

Change the invitation topic Change the invitation message Add and remove people from your participant list.

Add and remove people from your participant list.

Send the invitation to the users in the participant list.

Cancel and close the invitation

Figure 9-14 The outgoing invitation

Chapter 9. A complex meetings sample

231

For the outgoing invitation dialog we have two text boxes: one to place the topic for the invitation and the second for the message of the invitation. We also have an invitees list, which represents all the users this invitation will be sent to. A meeting tools frame is used to specify the tools that we want in our meeting; we can add and remove tools while we are writing the invitation. Finally, we have two more buttons: Send, to send the invitation, and Cancel, to cancel the invitation.

Construction and destruction


This class will be constructed and initialized by calling a single static call: OpenInvitation or OpenInvited depending on whether you want to open the incoming or outgoing invitation dialog. A parameter list for incoming invitations is in Table 9-7.
Table 9-7 OpenInvited static call parameters for incoming invitation
Parameter Post MeetingType Description The post object we received. The meeting type we are invited to.

A parameter list for outgoing invitations is in Table 9-8.


Table 9-8 OpenInvitation static call parameters for outgoing invitation
Parameter Post MeetingType Users list Session Description The post object to fill. The meeting type we want open. The list of the users we want to invite. The current session.

Managing activities
Activities are the tools we want to add to the Sametime Meeting. In the Meetings sample we define the activities in two phases. The first phase is defined at the MeetingUIDlg.cpp and represents the activities as they are defined on the server side. The second phase is a local define of the activities, which will help us to add and remove activities. Refer to Table 9-9 for local activities definitions.
Table 9-9 Local activities definitions
Activity CHAT_ACTIVITY AUDIO_ACTIVITY VIDEO_ACTIVITY ID 1 2 4 Description A Chat activity. An Audio activity. A Video activity.

232

Working with the Sametime Client Toolkits

Activity APPSHARE_ACTIVITY WHITEBORD_ACTIVITY

ID 8 16

Description An Application Sharing activity. A Whiteboard activity.

In Table 9-10 you can see the server activities definitions.


Table 9-10 Sametime Meeting Room Client (MRC) activities type
Activity ID CHAT_MRC_MEETING_ACTIVITY VIDEO_MRC_MEETING_ACTIVITY AUDIO_MRC_MEETING_ACTIVITY APPSHARE_MRC_MEETING_ACTIVITY WHITEBORD_MRC_MEETING_ACTIVITY Value 0x9106 0x9104 0x9103 0x9102 0x9101 Description Chat Activity. Video Activity. Audio Activity. Application Sharing Activity. Whiteboard Activity.

As you can see in Table 9-9, every activity ID is represented by a bit in five bits number. Therefore, if you, for example, want to pass a number which represents both CHAT_ACTIVITY and AUDIO_ACTIVITY you must use bitwise operator and the result will be: CHAT_ACTIVITY | VIDEO_ACTIVITY = 5.
Note: Different combinations of activities represent different meeting types. Refer to Example 9-20 on page 253 to see how we convert activities to meeting types.

InviteUIDlg.h
The InviteUIDlg.h file is shown in Example 9-6.
Example 9-6 InviteUIDlg
#if !defined __INVITE_UI_DLG__ #define __INVITE_UI_DLG__ #pragma warning (disable: 4786) #include "resource.h" #include <list> class Post; class AwarenessList; class STWatchedUser; using namespace std;

Chapter 9. A complex meetings sample

233

class InviteUIDlg : public CDialog { public: // Static methods static void OpenInvitation(Post& post, long lmeetingType, const list<STWatchedUser*>& lstInvitedUsers, STSession* pSTsession); static void OpenInvited(Post& post, long lMeetingType); //Destructor ~InviteUIDlg(); // Enums enum { IDD_INVITATION = IDD_INVITEUI_INVITATION_DLG , IDD_INVITED = IDD_INVITEUI_INVITED_DLG}; protected: // Overrides virtual void OnCancel(); virtual BOOL OnInitDialog(); virtual void DoDataExchange(CDataExchange* pDX); // Messages afx_msg void afx_msg void afx_msg void afx_msg void

OnSend(); OnJoin(); OnRespond(); OnInvitedClosed();

DECLARE_MESSAGE_MAP() private: //Private Constructors InviteUIDlg(Post& post ,long lmeetingType, const list<STWatchedUser*>* pLstInvitedUsers = NULL, STSession* pSTSession = NULL, bool bInvited = true); //Private functions void LoadInvitedInfoAndSettings(); void LoadInvitationInfoAndSettings(); CString GetMyUserName(); // Private members STSession* m_pSTSession; Post* m_pPost; AwarenessList* m_pInviteList; list<STWatchedUser*> m_lstInvitedUsers; CString m_strTopic; CString m_strMessage; CString m_strInviteText; bool m_bInvited; long m_lMeetingType;

234

Working with the Sametime Client Toolkits

}; #endif //__INVITE_UI_DLG__

9.2.6 The MeetingDlg class


The MeetingDlg class is responsible for the actual meeting functionality. In Figure 9-15 you can see its class diagram.

CDialog

CHtmlView

MeetingDlg

MyHtmlView

Figure 9-15 MeetingDlg class diagram

The MeetingDlg class is a basic browser class which we will use to launch the Meeting Room Client (MRC), the Audio/Video wizard, and the Audio/Video help. This class will inherit from the CDialog class and will hold a private member of MyHtmlView class. MyHtmlView class inherits from CHtmlView Mfc class, and will be used to show the HTML content on the MeetingDlg dialog. Figure 9-16 on page 236 shows what the actual meeting dialog looks like.

Chapter 9. A complex meetings sample

235

Figure 9-16 The Meeting dialog

Construction and destruction


We use a single constructor to construct and initialize the MeetingDlg class. The constructor will accept the following parameters: Meeting Type A long type which will represent the meeting type, this parameter will help us to determine what will be the size of the window. URL A string type which will represent the URL of the Meeting/Wizard/Help, we will use this string when we open the browser.

236

Working with the Sametime Client Toolkits

We will initialize our class size and private members in the OnInitDialog member function. The MyHtmlView class member will also get its size and URL to be navigated in this member function.

Changing the MeetingDlg window size


The MeetingDlg window and the HTML view sizes are determined by the meeting type we get in the constructor. The MeetingDlg class defines this rectangle in its cpp file. For the details of these defines according to meeting type, refer to Table 9-11.
Table 9-11 MeetingDlg size according to meeting type
Meeting type
ST_AUDIO_MEETING ST_VIDEO_MEETING ST_SHARE_MEETING ST_COLLABORATION_MEETING ST_AV_WIZARD_MEETING ST_HELP

Rectangle define
AUDIO_MEETING_DLG_RCT VIDEO_MEETING_DLG_RCT APPSHARE_MEETING_DLG_RCT COLLABORATE_MEETING_DLG_RCT AV_WIZARD_DLG_RCT HELP_DLG_RCT

Rectangle size
252x331 252x511 946x691 946x691 946x691 946x691

Navigating
To navigate to the URL that was provided by the constructor we simply use the Navigate2 member function of MyHtmView, which is an instance of the CHtmlView class. We call this member function after intializing the MyHtmlView private member in the OnInitDialog member function.

MeetingDlg.h
The MeetingDlg.h file is shown in Example 9-7.
Example 9-7 MeetingDlg.h
#if !defined __MEETING_DLG__ #define __MEETING_DLG__ #include "resource.h" #include <afxhtml.h> ////////////////////////// // MyHtmlView class MyHtmlView : public CHtmlView { public: MyHtmlView(){};

Chapter 9. A complex meetings sample

237

~MyHtmlView(){}; }; ////////////////////////// // MeetingDlg class MeetingDlg : public CDialog { public: //Constructor MeetingDlg(long lMeetingType, CString strUrl); // Destructor virtual ~MeetingDlg(); // Enums enum { IDD = IDD_MEETING_DLG}; protected: // Overrides virtual BOOL OnInitDialog(); virtual void OnCancel(); // Messages afx_msg void OnClose(); DECLARE_MESSAGE_MAP() private: //Private Methods CRect DlgRct2HtmlRct(CRect dlgRct); // Private members MyHtmlView* m_pHtmlView; CString m_strUrl; long m_lMeetingType; }; #endif // __MEETING_DLG__

238

Working with the Sametime Client Toolkits

9.3 Preparing the MeetingUI class


We now look at the dynamics of the MeetingUI class that we described in 9.2.1, The MeetingUI class on page 213.

9.3.1 Initialize MeetingUI class


The MeetingUI class will be used to create the meetings, which means that once we have a pointer for this class we can create a meeting with a single API call: CreateMeeting. This function will create the invitation dialog and once we send the invitation, it will create the place for us, and so on. The MeetingUI class is constructed and initialized with one static call :
AwarenessList.h. . . . MeetingUI* m_pMeetingUI; AwarenessList . . m_pMeetingUI = MeetingUI::Instance(pSTSession);

In the MeetingUI constructor we initialize all Sametime class members and listeners, as you can see in Example 9-8. The way we free all the members memory is shown in Example 9-9. As you can see, we dont free the memory of services members because this will be done when we free the memory of the STSession class member which is in the MeetingsApp class.
Example 9-8 MeetingUI constructor
MeetingUI::MeetingUI(STSession* pSTSession) :m_pSTSession(pSTSession), m_pPostService(NULL), m_pPlacesService(NULL), m_pTokenService(NULL), m_pMyPlacesServiceListener(NULL), m_pMyPostServiceListener(NULL), m_pMyTokenServiceListener(NULL), m_bServiceAvailable(false) { if (!m_pSTSession) return; m_pPostService = (PostService*) m_pSTSession->getComponent(POST_COMP_NAME);

Chapter 9. A complex meetings sample

239

m_pPlacesService = (PlacesService*)m_pSTSession->getComponent(PLACES_COMP_NAME); m_pTokenService = (TokenService*) m_pSTSession->getComponent(TOKEN_COMP_NAME); if (!m_pPostService) m_pPostService = new PostService(m_pSTSession); if (!m_pPlacesService) m_pPlacesService = new PlacesService(m_pSTSession); if (!m_pTokenService) m_pTokenService = new TokenService(m_pSTSession); m_pMyPostServiceListener = new MyPostServiceListener(this); m_pMyPlacesServiceListener = new MyMeetingUIPlacesServiceListener(this); m_pMyTokenServiceListener = new MyMeetingUITokenServiceListener(this); if (m_pPostService && m_pMyPostServiceListener) m_pPostService->addPostServiceListener(m_pMyPostServiceListener); if (m_pPlacesService && m_pMyPlacesServiceListener) m_pPlacesService->addPlacesServiceListener(m_pMyPlacesServiceListener); if (m_pPostService) m_pPostService->registerPostType(INVITATION_POST_TYPE); }

Example 9-9 MeetingUI destructor


MeetingUI::~MeetingUI() { if (m_pMyPostServiceListener) { if (m_pPostService) m_pPostService->removePostServiceListener(m_pMyPostServiceListener); delete m_pMyPostServiceListener; } if (m_pMyPlacesServiceListener) { if (m_pPlacesService) m_pPlacesService->removePlacesServiceListener(m_pMyPlacesServiceListener); delete m_pMyPlacesServiceListener; } m_pSTSession = NULL; m_pPostService = NULL; m_pPlacesService = NULL;

240

Working with the Sametime Client Toolkits

m_pMyPostServiceListener = NULL; m_pMyPlacesServiceListener = NULL; }

9.3.2 Calling MeetingUI API


MeetingUI class provides an API for creating meetings, opening the Audio/Video wizard, and opening the Audio/Video help, as shown in Example 9-10.
Example 9-10 MeetingUI API
// Api void void void bool CreateMeeting(list<STWatchedUser*> lstUsers ,long meetingType); OpenAVHelp(); OpenAVWizard(); IsMeetingsServiceAvailable();

To create Sametime Meetings, we just call the CreateMeeting API function from the AwarenessList.cpp. To create different Sametime Meetings, we just pass different Sametime Meeting Types (See Table 9-2 on page 214). The other parameters are the same. Refer to Example 9-11 to see how this is done in the AwarenessList class.
Example 9-11 Calling MeetingUI Api from AwarenessList.cpp
void AwarenessList::OpenChatWithSelectedUser() { int selectionCount = m_ctlAwarenessListView.GetSelectedCount(); if (selectionCount == 1 && m_pChatUI ) { STWatchedUser* pUser = GetSelectedUser(); m_pChatUI->Create1On1ChatById(*((STUser*)pUser)); return; } else { list<STWatchedUser*> lstUsers = GetSelectedUsers(); m_pMeetingUI->CreateMeeting(lstUsers,ST_CHAT_MEETING); } } . . . void AwarenessList::OnAudioPressed() { if (m_pMeetingUI) { m_pMeetingUI->CreateMeeting(GetSelectedUsers(),ST_AUDIO_MEETING);

Chapter 9. A complex meetings sample

241

} } void AwarenessList::OnVideoPressed() { if (m_pMeetingUI) { m_pMeetingUI->CreateMeeting(GetSelectedUsers(),ST_VIDEO_MEETING); } } void AwarenessList::OnSharePressed() { if (m_pMeetingUI) { m_pMeetingUI->CreateMeeting(GetSelectedUsers(),ST_SHARE_MEETING); } } void AwarenessList::OnCollaboratePressed() { if (m_pMeetingUI) { m_pMeetingUI->CreateMeeting(GetSelectedUsers(),ST_COLLABORATION_MEETING); } }

This concludes our description of the involved classes. We now look at the flow for creating the meetings.

9.4 Four steps to create the meetings


Our sample uses four basic steps to create and launch meetings. Figure 9-17 on page 243 shows the four steps: Creating the invitation Creating the place Generating a token Launching the Sametime Meeting client

242

Working with the Sametime Client Toolkits

Creating Sametime Meetings Using The C++ Toolkit


Creating The Invitation Creating The Place Generate Token Launch The Sametime Meeting
Creating new invitation Accepting an invitation

Post Service

Accepting The Invitation

Creating the invitation dialog Writing the data into the invitation Reading the data from the invitation

Sending the invitation

Creating the place

Joining the place

Joining The Place

Places Service

Creating the Meeting Launcher

Creating the NwayChat Dialog

Creating the Meeting Launcher

Entering a section

Chatting Adding tools

Adding activities to the place Changing attributes of the place Attribute Added

Activities added

Token Service

Generate Token

Generating Token

Token generated

Sametime Meeting Services

Launch The Sametime Meeting

Create the URL

Launch the browser to open the meeting

Figure 9-17 Creating Sametime meetings using the C++ Toolkit

As you can see, there are two routes we can navigate to create a Sametime meeting. The first route is on the left side of the diagram and is intended to create a meeting when we are the initiators of the meeting. The second route is on the right side of the diagram and is intended to launch an existing meeting once we got the invitation from another user.

Chapter 9. A complex meetings sample

243

Figure 9-17 also illustrates the four steps we need to go though when we want to create/launch a meeting. Each of the first three steps in the diagram is related to a specific service in the Sametime C++ toolkit: Post, Places, and Token services. Step four in the diagram is related to the URL creation and browser launching, and completes the whole picture of creating a meeting.

9.4.1 The invitation


The invitation is one of the basic steps for creating Sametime Meetings. To create/receive invitations we use the PostService API class. The PostService class provides us with the ability to create new or receive existing post objects; these will be used to create the invitations. The class that will create the invitations is the MeetingUI class, which holds a handle and a listener to the PostService. See Example 9-1 on page 215 for MeetingUI header file or Figure 9-7 on page 213 for an overview of the MeetingUI class. Because the MeetingUI class uses the PostService API class, it will have to try to get a pointer to it from the STSession class member, and if it fails, it will have to create a new PostService object passing it the STSession object. Once this is done we should register the invitation post type, which is defined as 25, as you can see at Example 9-12.
Example 9-12 Intializing PostService class member
MeetingUI::MeetingUI(STSession* pSTSession) { if (!m_pSTSession) return; m_pPostService = (PostService*) m_pSTSession->getComponent(POST_COMP_NAME); . . . if (!m_pPostService) m_pPostService = new PostService(m_pSTSession); . . . if (m_pPostService) m_pPostService->registerPostType(INVITATION_POST_TYPE); }

244

Working with the Sametime Client Toolkits

The invitation dialog


The invitation dialog will be used both for incoming and outgoing invitations. This dialog will be created and initialized by a single static call. Depending on the dialog we want to create (for incoming or outgoing invitations) we will use different API calls. We will call OpenInvitation for an outgoing invitation when we want to invite users to a meeting, and OpenInvited when we want to open an incoming invitation sent to us by another user. The InviteUIDlg has two resource templates: one for incoming invitations (IDD_INVITEUI_INVITATION_DLG) and one for outgoing invitations (IDD_INVITEUI_INVITED_DLG), as you can see at Example 9-13 and Figure 9-18.
Example 9-13 InviteUIDlg resource
class InviteUIDlg : public CDialog { . . . // Enums enum { IDD_INVITATION = IDD_INVITEUI_INVITATION_DLG , IDD_INVITED = IDD_INVITEUI_INVITED_DLG}; . . . };

Figure 9-18 InviteUIDlg class with two templates resource

Chapter 9. A complex meetings sample

245

For more information about using the InviteUIDlg class see The InviteUIDlg class on page 230.

Creating the invitation


We now look at creating the invitation. You can see in Figure 9-19 on page 246 where this happens.
Creating The Invitation Accepting The Invitation

Post Service

Creating new invitation

Accepting an invitation

Creating the invitation dialog Writing the data into the invitation Reading the data from the invitation

Sending the invitation

Figure 9-19 Create new invitation

Every invitation is based on a Post object we create or receive. In the Post object we put or get all the details of the invitation we create or recieve.

Create Post object


First we need to create a new Post object. Creating a Post object is done by using the PostService API- CreatePost passing the required post type (See Example 9-14). This type is a specific type of Sametime Invitation Type and is defined as 25 dec. We add this constant in the MeetingUI.cpp, as you can see in the following:
. . #define INVITATION_POST_TYPE 25 . .

Call the InviteUIDlg::OpenIvitation


Once we have created the invitation we need an invitation dialog, as shown in Figure 9-20 on page 247.

246

Working with the Sametime Client Toolkits

Figure 9-20 Creating the invitation dialog

We call the CreateInvitation static function of the InviteUIDlg class to construct and initialize the InviteUIDlg class. We need to provide four parameters: Post object Post object will represent the new invitation and will be sent at the end of the process. Meeting Type The meeting type we want to invite the other users to. (For a list of meeting types refer to Table 9-2 on page 214.) Users List A list of users we want to send the invitation to. STSession The current session. Refer to Example 9-14 to see how its done in the MeetingUI.cpp when the CreateMeeting API function is called.
Example 9-14 Creating a new InviteUIDlg class
void MeetingUI::CreateMeeting(list<STWatchedUser*> lstUsers, long meetingType) { Post post = m_pPostService->createPost(INVITATION_POST_TYPE); InviteUIDlg::OpenInvitation(post, meetingType, lstUsers,m_pSTSession); }

The InviteUIDlg::OpenInvitation member function


In the InviteUIDlg class the OpenInvitation call creates a new dialog. The type of the dialog is dependent on the API call which has been made. Refer to Example 9-15 to see how we handle this call.
Example 9-15 InviteUIDlg OpenInvitation static API call
void InviteUIDlg::OpenInvitation(Post& post, long lmeetingType, const list<STWatchedUser*>& lstInvitedUsers, STSession* pSTsession) { InviteUIDlg* pDlg = new InviteUIDlg (post,lmeetingType,&lstInvitedUsers,pSTsession,false); pDlg->Create(InviteUIDlg::IDD_INVITATION); pDlg->ShowWindow(SW_SHOW); }

Creating The Invitation

Accepting The Invitation

Post Service

Creating new invitation

Accepting an invitation

Creating the invitation dialog Writing the data into the invitation Reading the data from the invitation

Sending the invitation

Chapter 9. A complex meetings sample

247

The InviteUIDlg constructor


Once OpenInvitation is called, the InviteUIDlg constructor is called. In the constructor we intitialize all the InviteUIDlg class members and the dialog title and message, as shown in Example 9-16.
Example 9-16 InviteUIDlg constructor
InviteUIDlg::InviteUIDlg(Post& post, long lmeetingType, const list<STWatchedUser*>* pLstInvitedUsers, STSession* pSTSession, bool bInvited) : CDialog(bInvited ? InviteUIDlg::IDD_INVITED : InviteUIDlg::IDD_INVITATION, NULL), m_pSTSession(pSTSession), m_pPost(new Post(post)), m_lstInvitedUsers(pLstInvitedUsers ? *pLstInvitedUsers :list<STWatchedUser*>()), m_pInviteList(NULL), m_bInvited(bInvited), m_lMeetingType(lmeetingType) { CString strTitle,strMeetingType; switch (lmeetingType) { case ST_AUDIO_MEETING: strMeetingType = "Audio"; break; case ST_CHAT_MEETING: strMeetingType = "Chat"; break; case ST_SHARE_MEETING: strMeetingType = "AppShare"; break; case ST_VIDEO_MEETING: strMeetingType = "Video"; break; case ST_COLLABORATION_MEETING: strMeetingType = "Collaborate"; break; } strTitle.Format("%s's %s Meeting.",GetMyUserName(),strMeetingType); m_strTopic = _T(strTitle); }

248

Working with the Sametime Client Toolkits

OnInitDialog and LoadInvitationInfoAndSettings member functions


After the InviteUIDlg constructor is called, the InviteUIDlg::OnInitDialog is called. In the OnInitDialog member function we will initialize the dialog itself. Because we are creating a new invitation, we will call the InviteUIDlg::LoadInvitationInfoAndSettings member function, which will load the correct fields and controls to the dialog, as you can see in Example 9-17.
Example 9-17 LoadInvitationAndSettings member function
void InviteUIDlg::LoadInvitationInfoAndSettings() { if (!m_pInviteList && m_pSTSession) { CRect rct; GetDlgItem(IDC_STATIC_FOR_AWARENESS_LIST)->GetWindowRect(&rct); ScreenToClient(&rct); m_pInviteList = new AwarenessList(m_pSTSession, rct,this); m_pInviteList->Create(IDD_AWARENESS_LIST, this); m_pInviteList->ShowMenu(TRUE); m_pInviteList->EnableRemoving(TRUE); m_pInviteList->ShowWindow(SW_SHOW); list<STWatchedUser*>::iterator itr; for ( itr = m_lstInvitedUsers.begin() itr != m_lstInvitedUsers.end() itr++) m_pInviteList->AddUser(*itr); } ((CButton*)GetDlgItem(IDC_CHAT_CHECK))->SetCheck( ( m_lMeetingType == ST_COLLABORATION_MEETING m_lMeetingType == ST_CHAT_MEETING)); ((CButton*)GetDlgItem(IDC_SCREEN_SHARING_CHECK))->SetCheck( ( m_lMeetingType == ST_COLLABORATION_MEETING m_lMeetingType == ST_SHARE_MEETING)); ((CButton*)GetDlgItem(IDC_AUDIO_CHECK))->SetCheck( ( m_lMeetingType == ST_COLLABORATION_MEETING m_lMeetingType == ST_AUDIO_MEETING)); ((CButton*)GetDlgItem(IDC_VIDEO_CHECK))->SetCheck( ( m_lMeetingType == ST_COLLABORATION_MEETING m_lMeetingType == ST_VIDEO_MEETING)); ((CButton*)GetDlgItem(IDC_WHITEBOARD_CHECK))->SetCheck( ( m_lMeetingType == ST_COLLABORATION_MEETING m_lMeetingType == ST_SHARE_MEETING)); }

; ;

||

||

||

||

||

Chapter 9. A complex meetings sample

249

The invitees list


Because the case here is that we are creating a new invitation, we would like to have a participant list of all the users we want to invite to the meeting. To create the participant list we will use the AwarenessList class, which will provide us the capabilities of live names list of all the users we want to invite. The AwarenessList class is also used in the MainAppDlg class to show our buddy list and in the AddDlg class when a conflict occurs. For more information about the AwarenessList class refer to the Tutorial at the start of the LiveNames sample. Once the dialog is created the user can add and remove meeting tools, change the topic and the message of the invitation, add and remove users from the participant list, and send the invitation, as shown in Figure 9-21.

Change the invitation topic Change the invitation message Add and remove people from your participant list.

Add and remove people from your participant list.

Send the invitation to the users in the participant list.

Cancel and close the invitation

Figure 9-21 Invitation dialog description

Example 9-18 shows the code which will be executed when the Send button is pressed.

250

Working with the Sametime Client Toolkits

Example 9-18 InviteUIDlg::OnSend member function


void InviteUIDlg::OnSend() { UpdateData(); long lActivities = 0; lActivities = (((CButton*)GetDlgItem(IDC_CHAT_CHECK))->GetCheck()) ? lActivities | CHAT_ACTIVITY : lActivities; lActivities = (((CButton*)GetDlgItem(IDC_SCREEN_SHARING_CHECK))->GetCheck()) ? lActivities | APPSHARE_ACTIVITY : lActivities; lActivities = (((CButton*)GetDlgItem(IDC_WHITEBOARD_CHECK))->GetCheck()) ? lActivities | WHITEBORD_ACTIVITY : lActivities; lActivities = (((CButton*)GetDlgItem(IDC_AUDIO_CHECK))->GetCheck()) ? lActivities | AUDIO_ACTIVITY : lActivities; lActivities = (((CButton*)GetDlgItem(IDC_VIDEO_CHECK))->GetCheck()) ? lActivities | VIDEO_ACTIVITY : lActivities; bool b1On1 = true; if (m_pPost) { BSTR bstr; m_pPost->setTitle(bstr = m_strTopic.AllocSysString()); ::SysFreeString(bstr); m_pPost->setMessage(bstr = m_strMessage.AllocSysString()); ::SysFreeString(bstr); if (m_pInviteList) { list<STWatchedUser*> lstUsers = m_pInviteList->GetAllUsers(); list<STWatchedUser*>::iterator itr; for ( itr = lstUsers.begin(); itr != lstUsers.end() ; itr++) if (*itr) m_pPost->addUser(**itr); if (m_pInviteList->GetAllUsers().size() > 2 ) b1On1 = false; } } MeetingUI* pMeetingUII = MeetingUI::Instance(); if (pMeetingUII) { pMeetingUII->OnSend(m_pPost,lActivities,b1On1); pMeetingUII->Destroy(); } DestroyWindow(); delete this; }

Chapter 9. A complex meetings sample

251

As you can see in Example 9-18, the first thing done after updating the dialog members is to find out what activities we would like to add to the meeting. This is done by checking each control to see if it is marked, and if so, we mark (by using bitwise) the specific bit in lActivities member which will represent all the activities we want to add to the meeting. After we find out what activities we want to add, we set the post object title and message as they appear in the invitation dialog. This is done by calling Post::setTitle and Post::setMessage. Finally, we want to tell the post object who are the users we want this post (Invitation) to be sent to, so we run through the participant list and add each user to the post object by using the AwarenessList::GetAllUsers and Post::addUser member functions. After we provide the post object all the relevant details (title, message, and users), we pass this information to the MeetingUI class to handle the Send request. Example 9-19 shows the code which is executed once the MeetingUI::OnSend member function is called.
Example 9-19 MeetingUI::OnSend member function
void MeetingUI::OnSend(Post* pPost, long lActivities, bool b1On1) { STStream dataPack; //Data Structure long lMeetingType = GetMeetingTypeFromActivities(lActivities); if (lMeetingType == ST_MEETING_TYPE_ERROR) return; unsigned short usEncryptionLevel = ST_ENC_LEVEL_RC2_40; wstring wstrPlaceName = GetUniquePlaceName(); wstring wstrPassword = L""; CString serverName = GetServerName(); BSTR bstr = serverName.AllocSysString(); wstring wstrServerName(bstr); bool bAutoInvite = false; unsigned long mark(0);

dataPack<<mark<<lMeetingType<<b1On1<<usEncryptionLevel<<wstrPlaceName<<wstrPass word<<wstrServerName<<bAutoInvite; bool bInviteByPlace(false); wstring strInvitorName(L""); wstring strUserId(L""); wstring strCommunityName(L""); long lPortOfSSL(0); dataPack<<bInviteByPlace<<strInvitorName<<strUserId<<strCommunityName<<lPortOfS SL<<mark; //Modify && send the post if (pPost)

252

Working with the Sametime Client Toolkits

{ pPost->setDetailsType(0); pPost->setDetails(dataPack); pPost->send(); } . . . ::SysFreeString(bstr); }

Once the MeetingUI::OnSend member function is called by the InviteUIDlg class and passes the post, activities, and identifier parameters, the MeetingUI::OnSend member function goes through the following four steps: 1. Translate the activities member to a meeting type. 2. Build the data structure. 3. Send the invitation. 4. Create and enter the place. These steps are described in detail in the following sections.

Translate the activities member to a meeting type


The MeetingUI::GetMeetingTypeFromActivities member function gets a long parameter which represents the activities we want to have in our meeting and translates it to a meeting type, as shown Example 9-20.
Example 9-20 MeetingUI::GetMeetingTypeFromActivities member function
long MeetingUI::GetMeetingTypeFromActivities(long lActivities) { long meetingType = ST_MEETING_TYPE_ERROR; if ( lActivities & CHAT_ACTIVITY && lActivities > CHAT_ACTIVITY) meetingType = ST_COLLABORATION_MEETING; else if ( lActivities & AUDIO_ACTIVITY && lActivities & VIDEO_ACTIVITY && lActivities == (AUDIO_ACTIVITY | VIDEO_ACTIVITY)) meetingType = ST_VIDEO_MEETING; else if ( lActivities & APPSHARE_ACTIVITY && lActivities & WHITEBORD_ACTIVITY&& lActivities == (APPSHARE_ACTIVITY | WHITEBORD_ACTIVITY)) meetingType = ST_SHARE_MEETING; else if ( lActivities & CHAT_ACTIVITY && lActivities == CHAT_ACTIVITY ) meetingType = ST_CHAT_MEETING;

Chapter 9. A complex meetings sample

253

else if ( lActivities & AUDIO_ACTIVITY && lActivities == AUDIO_ACTIVITY ) meetingType = ST_AUDIO_MEETING; else if ( lActivities & VIDEO_ACTIVITY && lActivities == VIDEO_ACTIVITY ) meetingType = ST_VIDEO_MEETING; else if ( lActivities & APPSHARE_ACTIVITY && lActivities == APPSHARE_ACTIVITY ) meetingType = ST_SHARE_MEETING; else if ( lActivities > 0) meetingType = ST_COLLABORATION_MEETING; return meetingType; }

Build and set the data structure


Creating The Invitation

Post Service

Accepting The Invitation

Creating new invitation

Accepting an invitation

Creating the invitation dialog Writing the data into the invitation Reading the data from the invitation

Sending the invitation

Figure 9-22 Write the data into the invitation

The second thing MeetingUI::OnSend does is wrap some additional data into the data structure by using STStream class (See the Reference Guide for more details on STStream class) and set the post object with this data. The additional data we wrap using the STStream class is used to give the users who get the invitation some important data, like encryption level, server name, place name, and more. For details about how the data should be packed, refer to Table 9-12.
Important: The order in which the data is packed is important and should be as described in Table 9-12. Other data structures wont be accepted by standard Sametime clients and the invitation wont be accepted.
Table 9-12 Data structure to send with the invitation
No 1 2 Name Mark Meeting Type Type long (4 bytes) long (4 bytes) Description Marks the beginning of data structure - Must be 0. The meeting type we want to invite the other users to.

254

Working with the Sametime Client Toolkits

No 3 4 5 6 7 8 9 10 11 12

Name One On One Encryption Level Place Name Password Server Name Invited By Place Invitation Name User Id Community Name Port Of SSL

Type bool (1 byte) unsigned short (2 bytes) wstring wstring wstring bool wstring wstring wstring long (4 bytes)

Description Identify if this is 1On1 meeting or more users were invited. Identify the encryption level we want our meeting to have. Identify the place name where the meeting will take place. The place password if we want to protect the meeting with a password. The server name where the meeting will take place. For internal use. (Just put empty wstring.) For internal use. (Just put empty wstring.) For internal use. (Just put empty wstring.) For internal use. (Just put empty wstring.) The port of SSL when the meeting is created using SSL support, if not this value must be 0. Marks the end of data structure.

13

Mark

long (4 bytes)

After creating the data structure we use Post::setDetails to set this data to the post object and Post::setDetailsType to set the post data type.

Chapter 9. A complex meetings sample

255

Send the invitation


Creating The Invitation Creating The Invitation

Post Service

Accepting The Invitation

Creating new invitation

Accepting an invitation

Creating the invitation dialog Writing the data into the invitation Reading the data from the invitation

Sending the invitation

Figure 9-23 Send the invitation

Once the post object has all the data it needs, this post can finally be sent. This is done by calling Post::Send member function. Thats it; the Invitation was sent.

Create and enter the place


This step is discussed in 9.4.2, The place on page 264.

Accepting the invitation


We now look at the case where the user is accepting an invitation, as shown in Figure 9-24.

Post Service

Accepting The Invitation

Creating new invitation

Accepting an invitation

Creating the invitation dialog Writing the data into the invitation Reading the data from the invitation

Sending the invitation

Figure 9-24 Accepting the invitation

Accepting an invitation means that we have to listen for incoming posts. To listen for incoming posts we use the Post Service by adding a PostServiceListener listener and registering the specific post type we want the PostServiceListener to notify us with. In Example 9-12 on page 244 you can see how this is done in the MeetingUI constructor. Next we need to create a new PostServiceListener and add it to the PostService. Example 9-21 on page 257 shows how this is done in the MeetingUI constructor.

256

Working with the Sametime Client Toolkits

Example 9-21 Creating and Adding PostServiceListener


MeetingUI::MeetingUI(STSession* pSTSession) { . . m_pMyPostServiceListener = new MyPostServiceListener(this); if (m_pPostService && m_pMyPostServiceListener) . . . }

Once the PostServicelistener::posted member function is called, the MeetingUI::Posted member function is also called, as you can see in Example 9-22 and Example 9-23.
Example 9-22 MyPostServiceListener::posted member function
void MyPostServiceListener::posted(PostEvent event) { if (m_pCallBack) m_pCallBack->Posted(event); }

Example 9-23 MeetingUI::Posted member function


void MeetingUI::Posted(PostEvent event) { if (CString(event.getPost().getSenderDetails().GetName().c_str()) == GetMyUserName()) return; if (event.getPost().getType() == INVITATION_POST_TYPE) { Post& post = event.getPost(); STStream dataPack = post.getDetails(); unsigned long mark(0); long lMeetingType; dataPack>>mark>>lMeetingType; InviteUIDlg::OpenInvited(event.getPost(),lMeetingType); } }

Chapter 9. A complex meetings sample

257

As you can see in Example 9-23, once the MeetingUI::Posted member function is called, the first thing we do is to check that the post is not one sent mistakenly by us. Next we check if the post type of the post is the valid post type we defined in Creating the invitation on page 246. Then we take out from the event the post object, the post type from the details, and finally, call the InviteUIDlg::OpenInvited static member function with all these parameters to open the Invitation dialog with the correct parameters.

The InviteUIDlg::OpenInvited member function


Creating The Invitation

Post Service

Accepting The Invitation

Creating new invitation

Accepting an invitation

Creating the invitation dialog Writing the data into the invitation Reading the data from the invitation

Sending the invitation

Figure 9-25 Create the invitation dialog

Example 9-24 shows the code once the InviteUIDlg::OpenInvited static member function is called.
Example 9-24 InviteUIDlg::OpenInvited member function
void InviteUIDlg:: OpenInvited(Post& post, long lMeetingType) { InviteUIDlg* pDlg = new InviteUIDlg(post,lMeetingType); pDlg->Create(InviteUIDlg::IDD_INVITED); pDlg->ShowWindow(SW_SHOW); }

After creating a new InviteUIDlg dialog, InviteUIDlg constructor is called, as you can see in Example 9-16 on page 248. And once we called the InviteUIDlg::Create member function, the InviteUIDlg::OnInitDialog member function is called, as shown in Example 9-25.

258

Working with the Sametime Client Toolkits

The OnInitDialog and LoadInvitedInfoAndSettings fuctions


Creating The Invitation

Post Service

Accepting The Invitation

Creating new invitation

Accepting an invitation

Creating the invitation dialog Writing the data into the invitation Reading the data from the invitation

Sending the invitation

Figure 9-26 Reading the data from the invitation

Example 9-25 InviteUIDlg::OnInitDialog member function


BOOL InviteUIDlg::OnInitDialog() { if (m_bInvited) LoadInvitedInfoAndSettings(); else LoadInvitationInfoAndSettings(); return CDialog::OnInitDialog(); }

As you can see in Example 9-25, because its an Invited dialog, which means that we were invited to the meeting, the LoadInvitedInfoAndSettings member function is called to modify and update the dialog controls with the invitation data. This is shown in Example 9-26.
Example 9-26 InviteUIDlg::LoadInvitedInfoAndSettings member function
void InviteUIDlg::LoadInvitedInfoAndSettings() { STUserInstance sender; CString senderName = _T(""); CString invitationTitle = _T(""); CString invitationMessage = _T(""); CString topicMsg = _T(""); CString meetingTypeMsg = _T(""); int iMeetingIcon = 0; if (m_lMeetingType == ST_COLLABORATION_MEETING) { meetingTypeMsg = "Collaborate"; iMeetingIcon = IDI_COLLABORATE_MEETING_ICON; } else if (m_lMeetingType == ST_SHARE_MEETING)

Chapter 9. A complex meetings sample

259

{ meetingTypeMsg = "Application Sharing"; iMeetingIcon = IDI_SHARE_MEETING_ICON; } else if (m_lMeetingType == ST_VIDEO_MEETING) { meetingTypeMsg = "Video"; iMeetingIcon = IDI_VIDEO_MEETING_ICON; } else if (m_lMeetingType == ST_AUDIO_MEETING) { meetingTypeMsg = "Audio"; iMeetingIcon = IDI_AUDIO_MEETING_ICON; } else if (m_lMeetingType == ST_CHAT_MEETING) { meetingTypeMsg = "Chat"; iMeetingIcon = IDI_CHAT_MEETING_ICON; } if (iMeetingIcon != 0) { HICON hIcon = AfxGetApp()->LoadIcon(iMeetingIcon); if (hIcon) ((CStatic*)(GetDlgItem(IDC_MEETING_TYPE_ICON)))->SetIcon(hIcon); } if (m_pPost) { sender = m_pPost->getSenderDetails(); senderName = sender.GetName().c_str(); invitationTitle = m_pPost->getTitle().c_str(); invitationMessage = m_pPost->getMessage().c_str(); topicMsg.Format("%s is inviting you to a %s meeting",senderName,meetingTypeMsg); m_strInviteText.Format("Topic: %s\r\nMessage: %s",invitationTitle,invitationMessage); } GetDlgItem(IDC_YOU_ARE_INVITED)->SetWindowText(topicMsg); UpdateData(FALSE); }

In Example 9-26 we set the dialog meeting type, topic, and message fields according to the data we get from the post object, which is the invitation data. Once the dialog appears, we will see all the invitation data as it was sent. This is shown in Figure 9-27.

260

Working with the Sametime Client Toolkits

The invitation type. The invitation topic and message

Icon which identify the type of the meeting

Click here to accept the invitation and join the meeting.

Click here to if you want to respond to the invitation this will open Im to the user who sent the Invitation.

Click here to decline the invitation and close the dialog.

Figure 9-27 Invited dialog description

Once the dialog appears, the user has three choices: accept the invitation and Join the meeting, Respond to the invitation by opening an Im to the user who sent the invitation (this action wont close the dialog), or Close to decline the invitation and close the dialog.

Join
Once the user chooses to join the meeting, the InviteUIDlg::OnJoin member function is called. This is shown in Example 9-27.
Example 9-27 InviteUIDlg::OnJoin member function
void InviteUIDlg::OnJoin() { MeetingUI* pMeetingUI = MeetingUI::Instance(); if (pMeetingUI) { pMeetingUI->OnJoin(m_pPost); pMeetingUI->Destroy(); } DestroyWindow(); delete this; }

As you can see in Example 9-27, the InviteUIDlg::OnJoin calls the MeetingUI::OnJoin, passing him the post parameter to handle the request of joining the meeting. This is shown in Example 9-28 on page 262.

Chapter 9. A complex meetings sample

261

Example 9-28 MeetingUI::OnJoin member function


void MeetingUI::OnJoin(Post* pPost) { if (!pPost) return; STStream dataPack = pPost->getDetails(); //Data struct long lMeetingType; bool b1On1; unsigned short usEncryptionLevel; bool bAutoInvite; wstring wstrPlaceName; wstring wstrPassword; wstring wstrServername; unsigned long mark(0); //Get the data dataPack>>mark>>lMeetingType>>b1On1>>usEncryptionLevel>>wstrPlaceName>>wstrPass word>>wstrServername>>bAutoInvite>>mark; if(lMeetingType == ST_MEETING_TYPE_ERROR) return; //Create the place Place place = m_pPlacesService->createPlace(wstrPlaceName, pPost ? pPost->getTitle() : L"", STEncLevel(usEncryptionLevel), SAMETIME_PLACE_TYPE, PlacesConstants::PLACE_PUBLISH_MODE_NOT_PUBLISHED); if (lMeetingType == ST_CHAT_MEETING) { //Create the dialog NWayChatUIDlg* pDlg = new NWayChatUIDlg( m_pSTSession , place , GetMyUserName() , false); } else { //Create the launcher MeetingLauncher* pLauncher = new MeetingLauncher( m_pSTSession , place, 0, lMeetingType, false); } }

262

Working with the Sametime Client Toolkits

Example 9-28 shows how the MeetingUI::OnJoin member function first extracts all the data from the post object so we know to what place we are to join, what the password is, and so on. This data structure is similar to the data structure described on Table 9-12 on page 254. You must pull the data out the same way you put it in when you created the invitation. Next, the MeetingUI::OnJoin member function joins the place based on the data it gets from the post object. For more details on joining a place see 9.4.2, The place on page 264.

Respond
Once the user clicks the Respond button, the InviteUIDlg::OnRespond member function is called. InviteUIDlg::OnRespond calls the MeetingUI::OnRespond member function and passes it the post object to handle the request, as you can see in Example 9-29.
Example 9-29 InviteUIDlg::OnRespond member function
void InviteUIDlg::OnRespond() { MeetingUI* pMeetingUI = MeetingUI::Instance(); if (pMeetingUI) { pMeetingUI->OnRespond(m_pPost); pMeetingUI->Destroy(); } }

Once the MeetingUI::OnRespond member function is called, it uses the ChatUI::Create1On1ChatById member function to create Chat with the user who sent the post. This is shown in Example 9-30. For more information about the ChatUI class, refer to the ExtLiveNames sample in the C++ toolkit tutorial.
Example 9-30 MeetingUI::OnRespond member function
void MeetingUI::OnRespond(Post* pPost) { ChatUI* pChatUI = ChatUI::Instance(); if (pChatUI && pPost) { STUserInstance user = pPost->getSenderDetails(); STUser* pUser = (STUser*)&user; pChatUI->Create1On1ChatById(*pUser); pChatUI->Destroy(); } }

Chapter 9. A complex meetings sample

263

Once the chat dialog appears, the user can ask questions about the invitation directed to the user who sent the invitation. When the user is finished responding to the invitation, he still can decide to Join or to Close the invitation.

Close
If the user chooses to close the invitation, the InviteUIDlg is destroyed, along with its members, including the post object, which means that this user declined to join the meeting.

9.4.2 The place


In the physical world, when we want to meet other people, we need to have a place where we can meet, see each other, talk, and exchange data. In Sametime, we meet in a virtual place where we can see each other talk and even exchange some data between us. The only difference between real life and Sametime is that in Sametime we have to create this place. As youll see later in this chapter, creating the place or joining an existing place is not a complex process and can be done very easily if we understand the Places architecture and API. Refer to Chapter 3, Places architecture on page 49 to learn more about the Places architecture.

Creating The Place


Creating The Place Joining The Place

Places Service

Creating the place

Joining the place

Creating the Meeting Launcher

Creating the NwayChat Dialog

Creating the Meeting Launcher

Entering a section

Chatting Adding tools Adding activities to the place Changing attributes of the place Activities added Attribute Added

Figure 9-28 Creating the place

We will use the PlaceService::CreatePlace member function to create a place, providing it with the following parameters: Place Name The unique place name we want our place to have (see Example 9-19 on page 252 and Example 9-31 on page 265).

264

Working with the Sametime Client Toolkits

Place Display Name The display name we want to provide for the place, this name can be displayed, for example, as the title of the window. Encryption Level The encryption level we want our place to have. See Table 9-13 on page 266 for a list of all Encryption Levels IDs. Place Type The Place type we want our place to have. In our case this type is 0 and is defined as SAMETIME_PLACE_TYPE = 0. Publish Mode The publish mode we want our place to have, for example if we want our place to be a public place or not. See Table 9-14 on page 266 for a list of all publish modes. The following code shows how we do this in the Meetings Sample on MeetingUI::OnSend at the time we have all the information we need from the invitation. (Refer to Example 9-19 on page 252 for the entire code.)
. . . Place place = m_pPlacesService->createPlace(wstrPlaceName, pPost ? pPost->getTitle() : L"", STEncLevel(usEncryptionLevel), SAMETIME_PLACE_TYPE, PlacesConstants::PLACE_PUBLISH_MODE_NOT_PUBLISHED); . . .

Example 9-31 Generating a unique place name using the MeetingUI::GetUniquePlaceName member function
wstring MeetingUI::GetUniquePlaceName() { static long id; CString strId; time_t t = CTime::GetCurrentTime().GetTime(); strId.Format("%S%ld%ld",GetMyUserId().c_str(),++id*rand(),t); BSTR bstrId = strId.AllocSysString(); wstring wstrId(bstrId); ::SysFreeString(bstrId); return wstrId; }

Chapter 9. A complex meetings sample

265

Table 9-13 Encryption level IDs


Encryption level ID ST_ENC_LEVEL_NONE ST_ENC_LEVEL_DONT_CARE ST_ENC_LEVEL_ALL ST_ENC_LEVEL_RC2_40 ST_ENC_LEVEL_RC2_128 Value 0 1 2 0x1000 0x2000 Encryption level description No encryption. May or may not be encrypted. Any type of encryption. Encryption using RC2, 40 bit. Encryption using RC2, 128 bit, with Diffie-Hellman.

Table 9-14 Place Publish Modes


Publish Mode ID PLACE_PUBLISH_MODE_PUBLISHED PLACE_PUBLISH_MODE_NOT_PUBLISHED, PLACE_PUBLISH_MODE_DONT_CARE Value 0 1 2 Description Publish mode for a published place. Publish mode for an unpublished place. Publish mode for those who are not concerned whether the place is public or not.

The next thing is to join the place if you are an invitee.

Joining The Place


We will now look at how we join an existing place, as you can see in Figure 9-29.
Creating The Place Joining The Place

Places Service

Creating the place

Joining the place

Creating the Meeting Launcher

Creating the NwayChat Dialog

Creating the Meeting Launcher

Entering a section Chatting Adding tools Adding activities to the place Changing attributes of the place Activities added Attribute Added

Figure 9-29 Joining the place

266

Working with the Sametime Client Toolkits

Joining an existing place means that when we enter the place we will enter the place in join mode. The place object is created the same as if we created a new place. The main difference is that here we get all the parameters for creating the place from the invitation we received from the user who invited us. Refer to Example 9-28 on page 262 to see how this was done in the MeetingUI::OnJoin member function when we decided to join the place. Also refer to the next section to see the difference between creating and joining a place.

Entering the place


After successfully creating a place object, the first thing we would like to do using the place object is to enter the place. Entering a place can be done in several modes. Table 9-15 identifies the entering modes.
Table 9-15 Entering place modes
Creation Mode ID PLACE_CREATION_MODE_CREATE Value 0 Description Creation mode used to enter a new place if the place does not already exist. Creation mode that is used to join an existing place. Creation mode for those who are not concerned whether the place is created or joined.

PLACE_CREATION_MODE_JOIN PLACE_CREATION_MODE_DONT_CARE

1 2

In Example 9-32 you can see how we enter a place in the MeetingController constructor (For more details about MeetingController class, refer to 9.2.2, The MeetingController class on page 217).
Example 9-32 MeetingController Constructor
MeetingController::MeetingController(STSession* pSTSession, const Place& place, long lActivities, long lMeetingType, bool bInitiator) :m_pPlace(new Place(place)), m_pPlaceListener(NULL), m_pTokenService(NULL), m_pPlacesService(NULL), m_pTokenServiceListener(NULL), m_pPlaceServiceListener(NULL), m_lActivities(lActivities), m_lMeetingType(lMeetingType), m_bInitiator(bInitiator), m_bActivityAdded(false) { m_pPlaceListener = new MyPlaceListener(this); if (m_pPlace && m_pPlaceListener) {

Chapter 9. A complex meetings sample

267

m_pPlace->addPlaceListener(m_pPlaceListener); if (m_bInitiator) m_pPlace->enter(L"",PlacesConstants::PLACE_CREATION_MODE_CREATE,true); else m_pPlace->enter(L"",PlacesConstants::PLACE_CREATION_MODE_JOIN,true); } if (pSTSession) { m_pTokenService = (TokenService*)(pSTSession->getComponent(TOKEN_COMP_NAME)); if (!m_pTokenService) m_pTokenService = new TokenService(pSTSession); m_pPlacesService = (PlacesService*)(pSTSession->getComponent(PLACES_COMP_NAME)); if (!m_pPlacesService) m_pPlacesService = new PlacesService(pSTSession); m_pPlaceServiceListener = new MyMeetingControllerPlacesServiceListener(this); m_pPlacesService->addPlacesServiceListener(m_pPlaceServiceListener); } m_pTokenServiceListener = new MyMeetingControllerTokenServiceListener(this); }

Creating the NWayChat dialog


We are now ready to create the window for our chat meeting (NWay chat).
Joining The Place Creating The Place

Places Service

Creating the place

Joining the place

Creating the Meeting Launcher

Creating the NwayChat Dialog

Creating the Meeting Launcher

Entering a section

Chatting Adding tools Adding activities to the place Changing attributes of the place Activities added Attribute Added

Figure 9-30 Creating the NWayChat Dialog

268

Working with the Sametime Client Toolkits

We create the NWay-Chat Dialog when the meeting type we get from the invitation is chat. There are two cases when we will create the NWay-Chat Dilaog: when we invite other users to an NWayChat meeting, and when we were invited to a chat meeting. We create the NWayChatUIDlg with the same parameters in both cases, with only one difference. This difference is the initiator parameter, which is true if we are the initiators of the place and false otherwise. Refer to 9.2.3, The NWayChatUIDlg class on page 221 for an overview of the NWayChatUIDlg class, and to 9.2.2, The MeetingController class on page 217 for an overview on the MeetingController class. Example 9-19 on page 252 and Example 9-28 on page 262 show how the NWayChatUIDlg is created in each one of the cases. When the NWayChatUIDlg constructor is launched, it calls its parent class constructor, which is the MeetingController constructor. You can see this in Example 9-33.
Example 9-33 NWayChatUIDlg Constructor
NWayChatUIDlg::NWayChatUIDlg(STSession* pSTSession, const Place& place, CString strMyName, bool bInitiator) :CDialog(NWayChatUIDlg::IDD, NULL), MeetingController(pSTSession,place,CHAT_ACTIVITY,ST_CHAT_MEETING, bInitiator), m_pSection(NULL), m_pMyselfInPlace(NULL), m_pMySectionListener(NULL), m_pMyMyselfInPlaceListener(NULL), m_pParticipantList(NULL), m_pMyUserInPlaceListener(NULL), m_strMyName(strMyName), m_pAddToolsDlg(NULL) { }

Once the MeetingController constructor has been called, we create a place listener and add it to the place object, which is kept as a member in the MeetingController class. Next we add a PlaceService listener to the place service handle, which we also have as a member in the MeetingController class. See Example 9-32 on page 267 to see how its done. Once we passed both NWayChatUIDlg and MeetingController constructors and we sent the place object a request to enter the place, we have to wait for the Entered event and then the MyPlaceListener::sectionAdded events to continue with the process. Once the MyPlaceListener::entered member function has been called, the NWayChatUIDl::OnEnterd member function is called, as you can see in Example 9-34 and Example 9-35 on page 270.

Chapter 9. A complex meetings sample

269

Example 9-34 MyPlaceListener::entered member function


void MyPlaceListener::entered(PlaceEvent event) { if (m_pCallBack) m_pCallBack->OnEntered(event); }

Now look at Example 9-35. Once the NWayChatUIDlg::OnEntered has been called, we call the Create and ShowWindow member functions to create the dialog. This is done here because we dont want our dialog to be displayed before we are sure we entered the place.
Example 9-35 NWayChatUIDlg::OnEntered member function
void NWayChatUIDlg::OnEntered(PlaceEvent event) { Create(IDD_NWAY_CHAT_DLG); ShowWindow(SW_SHOW); BringWindowToTop(); if (m_hWnd) SetWindowText(CString(event.getPlace().getDisplayName().c_str())); if (!m_pMyUserInPlaceListener) m_pMyUserInPlaceListener = new MyUserInPlaceListener(this); }

There is also the possibility that we will fail entering the place. In this case we would like to use the default behavior in the MeetingController base class so we wont override this member function (For more information about event handling between these two classes, refer to Table 9-4 on page 224.) Example 9-36 and Example 9-37 show how we handle this event.
Example 9-36 MyPlaceListener::enteredFailed member function
void MyPlaceListener::enterFailed(PlaceEvent event) { if (m_pCallBack) m_pCallBack->OnEnterFailed(event); }

270

Working with the Sametime Client Toolkits

Example 9-37 MeetingController::OnEnterFailed


void MeetingController::OnEnterFailed(PlaceEvent event) { long reason = event.getReason(); CString strMsg; strMsg.Format("Failed to enter the place. reason : 0x%x",reason); ::MessageBox(NULL,strMsg, "Sametime", MB_OK | MB_ICONEXCLAMATION); }

After calling the NWayChatUIDlg::Create member function in the NWayChatUIDlg::OnEnterd, we expect the NWayChatUIDlg::OnInitDialog to be called. Once this is done, as you can see in Example 9-38, we create the NWayChatUIDlg participant list, which is an AwarenessList class that gives us the support for live names. (Refer to the Tutorial start from the LiveNames sample for more information about the AwarenessList class.)
Example 9-38 NWayChatUIDlg::OnInitDialog member function
BOOL NWayChatUIDlg::OnInitDialog() { CDialog::OnInitDialog(); if (m_pPlace && m_pPlace->getSession()) { CRect rct; GetDlgItem(IDC_STATIC_FOR_AWARENESS_LIST)->GetWindowRect(&rct); ScreenToClient(&rct); m_pParticipantList = new AwarenessList(m_pPlace->getSession(), rct,this,AL_WRITING_NOTIFY); m_pParticipantList->Create(IDD_AWARENESS_LIST, this); m_pParticipantList->ShowMenu(TRUE); m_pParticipantList->EnableRemoving(FALSE); m_pParticipantList->ShowWindow(SW_SHOW); } return TRUE; }

Chapter 9. A complex meetings sample

271

Entering A Section
Creating The Place Joining The Place

Places Service

Creating the place

Joining the place

Creating the Meeting Launcher

Creating the NwayChat Dialog

Creating the Meeting Launcher

Entering a section

Chatting Adding tools Adding activities to the place Changing attributes of the place Activities added Attribute Added

Figure 9-31 Entering a section

When we called the Place::enterPlace member function, we passed several parameters, the last of which was if we want to go to the stage section. In all cases we enter the stage section. (For more information about sections in a place refer to 3.3.2, Sections on page 53). As we mentioned before, there are actually two events we are waiting for to continue with the process. One is the MyPlaceListenerEvent::entered, which we already handled, and the other is the MyPlaceListener::sectionAdded event. Once the MyPlaceListener::sectionAdded member function has been called, the NWayChatUIDlg::OnSectionAdded member function is called, as you can see in Example 9-39 and Example 9-40.
Example 9-39 MyPlaceListener::sectionAdded member function
void MyPlaceListener::sectionAdded(PlaceEvent event) { if (m_pCallBack) m_pCallBack->OnSectionAdded(event); }

Example 9-40 NWayChatUIDlg::OnSectionAdded member function


void NWayChatUIDlg::OnSectionAdded(PlaceEvent event) { if (!event.getSection().isStage() || m_pSection) return; m_pSection = new Section(event.getSection()); if (!m_pMySectionListener)

272

Working with the Sametime Client Toolkits

m_pMySectionListener = new MySectionListener(this); if (m_pSection && m_pMySectionListener) m_pSection->addSectionListener(m_pMySectionListener); }

Look at Example 9-40. The only section we are waiting for is the stage section, so with any event that carries section which is not the stage section, we return without doing anything. Once we get the stage section, we create a new section using the copy constructor of the section. After doing this, we add to this section a new section listener so we will get notifications from the section, like user entered and user left events, which are described in more details in the next chapter. The NWay-Chat dialog that appears will look like Figure 9-32 (except that we have added annotations here to describe its functionality).

This Meeting menu provides more functions to the meeting like Add Tools.

Transcript window which shows all the messages sent on the meeting.

This icon identify the user who is currently typing.

The meeting participant list shows all the users Who are currently in the meeting And their status.

This pane identify the incoming and outgoing of users from the meeting

Click here to send the message to the other users.

Click here to leave the meeting and close the dialog.

Figure 9-32 NWayChatUI dialog description

Chapter 9. A complex meetings sample

273

Monitoring user movements - entering and leaving the section


We would like to know about users who enter or leave the section so we know which users we are talking with. In the NWayChatUIDlg class we do this by adding or removing the users to or from the participant list. To retrieve these notifications we use the r SectionListener::userEntered and SectionListener::userLeft member functions. Example 9-41 and Example 9-42 illustrate how we handle the entrance of users and Example 9-43 and Example 9-44 show how we handle users leaving the section.
Example 9-41 MySectionListener::userEntered member function
void MySectionListener::usersEntered(SectionEvent event) { if (m_pCallBack) m_pCallBack->UsersEntered(event); }

Example 9-42 NWayChatUIDlg::UserEntered member function


void NWayChatUIDlg:: UsersEntered(SectionEvent event) { if (m_pParticipantList) { list<UserInPlace*> lstUsers = event.getUsers(); list<UserInPlace*>::iterator itr; for ( itr = lstUsers.begin() ; itr != lstUsers.end() ; itr++) { if (typeid(**itr) == typeid(MyselfInPlace) && !m_pMyselfInPlace) { if (m_pPlace) m_pMyselfInPlace = new MyselfInPlace(m_pPlace->getMyselfInPlace()); if (!m_pMyMyselfInPlaceListener) m_pMyMyselfInPlaceListener = new MyMyselfInPlaceListener(this); if (m_pMyselfInPlace && m_pMyMyselfInPlaceListener) m_pMyselfInPlace->addMyselfInPlaceListener(m_pMyMyselfInPlaceListener); } if (m_pMyUserInPlaceListener) { UserInPlace* pUserInPlace = new UserInPlace(**itr); if (pUserInPlace) { pUserInPlace->addUserInPlaceListener(m_pMyUserInPlaceListener); m_lstUsersInPlace.push_back(pUserInPlace); } }

274

Working with the Sametime Client Toolkits

m_pParticipantList->AddUser(*itr); if (m_hWnd && typeid(**itr) != typeid(MyselfInPlace)) { CString strUserName; strUserName.Format("%S joined the meeting.",(*itr)->GetName().c_str()); GetDlgItem(IDC_STATIC_STATUS)->SetWindowText(strUserName); } } } }

Example 9-43 MySectionListener::userLeft member function


void MySectionListener::userLeft(SectionEvent event) { if(m_pCallBack) m_pCallBack->UserLeft(event); }

Example 9-44 NWayChatUIDlg::UserLeft member function


void NWayChatUIDlg::UserLeft(SectionEvent event) { UserInPlace userInPlace = event.getUser(); if (m_pParticipantList) m_pParticipantList->RemoveUser(&(userInPlace)); list<UserInPlace*>::iterator itr; for ( itr = m_lstUsersInPlace.begin() ; itr != m_lstUsersInPlace.end() ; itr++) if (*itr && (*itr)->getMemberId() == userInPlace.getMemberId()) { (*itr)->removeUserInPlaceListener(m_pMyUserInPlaceListener); delete (UserInPlace*)*itr; m_lstUsersInPlace.remove(*itr); break; } if (m_hWnd) { CString strUserName; strUserName.Format("%S left the meeting.",event.getUser().GetName().c_str()); GetDlgItem(IDC_STATIC_STATUS)->SetWindowText(strUserName); } }

Chapter 9. A complex meetings sample

275

As you can see in Example 9-42 and Example 9-44, we use these notifications to change the text in the lower pane, which identifies the movements of users.

Chatting
Joining The Place Creating The Place

Places Service

Creating the place

Joining the place

Creating the Meeting Launcher

Creating the NwayChat Dialog

Creating the Meeting Launcher

Entering a section

Chatting Adding tools Adding activities to the place Changing attributes of the place Activities added Attribute Added

Figure 9-33 Chatting

To send text to the other users who are currently in the same section we just use the Section::sendText member function. Example 9-45 shows how this is done in the NWayCharUIDlg::OnSend member function.
Example 9-45 Sending text to the section on NWayChatUIDlg::OnSend member function
void NWayChatUIDlg::OnSend() { UpdateData(); BSTR bstr = m_strMessage.AllocSysString(); if (m_pSection) m_pSection->sendText(bstr); m_strMessage = ""; ::SysFreeString(bstr); UpdateData(FALSE); OnChangeEditMessage(); }

To receive Text which is sent to the section, we use the MyselfInPlaceListener, which will notify the NWayChatUIDlg class. Example 9-46 and Example 9-47 show how this is done.
Example 9-46 MyMyselfInPlaceListener::textReceived member function
void MyMyselfInPlaceListener::textReceived(MyselfEvent event) {

276

Working with the Sametime Client Toolkits

if (m_pCallBack) m_pCallBack->TextReceived(event); }

Example 9-47 NWayChatUIDlg::TextReceived member function


void NWayChatUIDlg::TextReceived(MyselfEvent event) { CString sender; if (event.getSender()) sender = ((UserInPlace*)event.getSender())->GetName().c_str(); CString strMsg; strMsg += "\r\n"; strMsg += sender; strMsg += " : "; strMsg += event.getText().c_str(); m_strTransScript += strMsg; UpdateData(FALSE); }

As you can see in Example 9-47, we call the MyselfEvent::getSender member function to get the user name of the user who sent the text so we can place it on the transcript window next to the text he sent.

Change my place attribute and listen to others attribute changes


Using the MySelfInPlace object we can change our own place attribute in this sample. In Sametime we use this to notify other users about the fact that we are typing a new message now, so everybody who will listen to this change will be notified. In this sample we use a Hand Typing icon to identify the user who is currently typing. Example 9-48 shows how we change our own attribute when we start typing and Example 9-49 on page 278 shows how we put an icon next to the person who changed his attribute. Example 9-50 shows how we remove the icon when the user removes this attribute. Note that we defined this attribute as 8 dec.
Example 9-48 NWayChatUIDlg::OnChangeEditMessage member function

void NWayChatUIDlg::OnChangeEditMessage() { CString str; GetDlgItem(IDC_EDIT_MESSAGE)->GetWindowText(str); if (m_pMyselfInPlace && str.GetLength() == 1) { STExtendedAttribute attribute(AwarenessList::USER_START_STOP_WRITING); m_pMyselfInPlace->changeAttribute(&attribute); }

Chapter 9. A complex meetings sample

277

else if (str.GetLength() <= 0) m_pMyselfInPlace->removeAttribute(AwarenessList::USER_START_STOP_WRITING); }

Example 9-49 NwayChatUIDlg::PlaceMemberAttributeChanged member function


void NWayChatUIDlg::PlaceMemberAttributeChanged(PlaceMemberEvent event) { UserInPlace* pUser = (UserInPlace*)event.getPlaceMember(); if (pUser && event.getAttributeKey() == AwarenessList::USER_START_STOP_WRITING && m_pParticipantList) m_pParticipantList->ChangeUserAttribute(pUser,AwarenessList::USER_START_STOP_WR ITING); }

Example 9-50 NWayChatUIDlg::placeMemberAttributeRemoved member function


void NWayChatUIDlg::PlaceMemberAttributeRemoved(PlaceMemberEvent event) { UserInPlace* pUser = (UserInPlace*)event.getPlaceMember(); if (pUser && event.getAttributeKey() == AwarenessList::USER_START_STOP_WRITING && m_pParticipantList) m_pParticipantList->ChangeUserAttribute(pUser,AwarenessList::USER_START_STOP_WR ITING,FALSE); }

278

Working with the Sametime Client Toolkits

Adding tools - The Add Tools dialog


We now look at the Add Tools dialog.
Creating The Place

Places Service

Joining The Place

Creating the place

Joining the place

Creating the Meeting Launcher

Creating the NwayChat Dialog

Creating the Meeting Launcher

Entering a section

Chatting Adding tools Adding activities to the place Changing attributes of the place Activities added Attribute Added

Figure 9-34 Adding tools

Adding tools to an existing chat meeting is an option that any user in a chat meeting can use. To open the Add Tools dialog from the NWay-Chat dialog, go to the Meeting menu and select the Add Tools option, as you can see in Figure 9-35.

Figure 9-35 Add Tools menu option

Chapter 9. A complex meetings sample

279

The Add Tools dialog appears, as shown in Figure 9-36.

Figure 9-36 The AddTools dialog

Note: The Add Tools dialog is a UI code-only class, so we will not describe it in much detail. If you want to see the full source code, you can download it from the IBM Redbooks Web site. See Appendix E, Additional Web material on page 407 for instructions.

Once the user clicks the Send button, the NWayChatUIDlg::OnSendTools member function is called, as you can see in Example 9-51.
Example 9-51 NWayChatUIDlg::OnSendTools member function
void NWayChatUIDlg::OnSendTools(long lActivities) { m_lActivities = lActivities; if (lActivities > CHAT_ACTIVITY) { m_lMeetingType = MeetingUI::GetMeetingTypeFromActivities(m_lActivities); PrepareTheMRC(); AddMRCActivitiesToPlace(); } }

As you can see in this example, the first thing we do is to translate the activities to a meeting type, as we did in Creating the invitation on page 246, so we can upgrade the meeting to a specific meeting type according to the tools we added. The second thing we do is call the MeetingController::AddMRCActivitiesToPlace member function, which is discussed in more detail in the next section.

280

Working with the Sametime Client Toolkits

Adding activities to the place


Joining The Place Creating The Place

Places Service

Creating the place

Joining the place

Creating the Meeting Launcher

Creating the NwayChat Dialog

Creating the Meeting Launcher

Entering a section Chatting Adding tools Adding activities to the place Changing attributes of the place Activities added Attribute Added

Figure 9-37 Adding activities to the place

One of the basic steps on the way to creating Sametime Meetings is adding activities to the place. The activities we add to the place are determined by what type of meeting we would like to have, or more precisely, by what the activities in this meeting will be. Note that the activities we want to add to the place must be supported by the server. For a general description of activities in a place refer to 3.3.3, Activities on page 53. Refer to Table 9-10 to see all Sametime Meeting Room Client (MRC) activities types. Example 9-52 illustrates how we add them to the place in the MeetingController::AddMRCActivitiesToPlace member function according to the activities the user wants to add to the meeting.
Example 9-52 MeetingController::AddMRCActivitiesToPlace member function
void MeetingController::AddMRCActivitiesToPlace() { if (!m_pPlace) return; if (m_lActivities & CHAT_ACTIVITY) m_pPlace->addActivity(CHAT_MRC_MEETING_ACTIVITY,STStream()); if (m_lActivities & AUDIO_ACTIVITY) m_pPlace->addActivity(AUDIO_MRC_MEETING_ACTIVITY,STStream()); if (m_lActivities & VIDEO_ACTIVITY) m_pPlace->addActivity(VIDEO_MRC_MEETING_ACTIVITY,STStream()); if (m_lActivities & APPSHARE_ACTIVITY) m_pPlace->addActivity(APPSHARE_MRC_MEETING_ACTIVITY,STStream());

Chapter 9. A complex meetings sample

281

if (m_lActivities & WHITEBORD_ACTIVITY) m_pPlace->addActivity(WHITEBORD_MRC_MEETING_ACTIVITY,STStream()); }

Changing attributes of the place


Creating The Place Joining The Place

Places Service

Creating the place

Joining the place

Creating the Meeting Launcher

Creating the NwayChat Dialog

Creating the Meeting Launcher

Entering a section

Chatting Adding tools Adding activities to the place Changing attributes of the place Activities added Attribute Added

Figure 9-38 Changing attributes of the place

Another step in creating Sametime Meetings is to change some place attributes. The MeetingController::PrepareTheMRC member function does all the attribute changes we need before we launch a Sametime Meeting, as shown in Example 9-53. The available MRC attribute IDs are identified in Table 9-16 on page 283.
Example 9-53 Changing place attributes - MeetingController::PrepareTheMRC member function
void MeetingController::PrepareTheMRC() { STStream dataPack; // Set the meeting kind dataPack<<MEETING_MODE_INSTANT; STExtendedAttribute attrMeeting(MEETING_STARTUP_MODE_ID,dataPack); if (m_pPlace) m_pPlace->changeAttribute(&attrMeeting); // Set the requested activities CString str = GetFormattedActivities(); BSTR bstr = str.AllocSysString(); wstring strAct(bstr);

282

Working with the Sametime Client Toolkits

dataPack.clear(); dataPack<<strAct; STExtendedAttribute attrRequest(MEETING_REQUEST_ACTIVITIES_ID,dataPack); if (m_pPlace) m_pPlace->changeAttribute(&attrRequest); ::SysFreeString(bstr); // Set the moderator ID MeetingUI* pMeetingUI = MeetingUI::Instance(); if (pMeetingUI) { wstring id = pMeetingUI->GetMyUserId(); wstring community(L""); dataPack.clear(); dataPack<<id<<community; STExtendedAttribute attrModerator(MEETING_MODEARATOR_ID,dataPack); if (m_pPlace) m_pPlace->changeAttribute(&attrModerator); } // Set the meeting time CTime time = CTime::GetCurrentTime(); time_t t = time.GetTime(); dataPack.clear(); dataPack<<t; STExtendedAttribute attrTime(MEETING_STARTING_TIME_ID,dataPack); if (m_pPlace) m_pPlace->changeAttribute(&attrTime); }

Table 9-16 MRC attribute IDs


Attribute ID MEETING_MODE_INSTANT MEETING_STARTUP_MODE_ID MEETING_REQUEST_ACTIVITIES_ID MEETING_MODEARATOR_ID MEETING_STARTING_TIME_ID Value 1 9004 9002 9005 9006

Chapter 9. A complex meetings sample

283

As you can see in Example 9-53, the MeetingController::PrepareTheMRC member function uses the MeetingController::GetFormattedActivities member function to translate all the required activities to a formatted string, so it can be set as an attribute to the place and the Meeting Room Client can read it. See Example 9-54.
Example 9-54 MeetingController::GetFormattedActivities member function
CString MeetingController::GetFormattedActivities() { CString tmp(""),strActivities(""); if (m_lActivities & CHAT_ACTIVITY) { tmp.Format("%ld,",CHAT_MRC_MEETING_ACTIVITY); strActivities +=tmp; } if (m_lActivities & AUDIO_ACTIVITY) { tmp.Format("%ld,",AUDIO_MRC_MEETING_ACTIVITY); strActivities +=tmp; } if (m_lActivities & VIDEO_ACTIVITY) { tmp.Format("%ld,",VIDEO_MRC_MEETING_ACTIVITY); strActivities +=tmp; } if (m_lActivities & APPSHARE_ACTIVITY) { tmp.Format("%ld,",APPSHARE_MRC_MEETING_ACTIVITY); strActivities +=tmp; } if (m_lActivities & WHITEBORD_ACTIVITY) { tmp.Format("%ld,",WHITEBORD_MRC_MEETING_ACTIVITY); strActivities +=tmp; } // Remove the last comma strActivities = strActivities.Left(strActivities.GetLength() - 1 ); return strActivities; }

284

Working with the Sametime Client Toolkits

Creating the Meeting launcher


Creating The Place Joining The Place

Places Service

Creating the place

Joining the place

Creating the Meeting Launcher

Creating the NwayChat Dialog

Creating the Meeting Launcher

Entering a section

Chatting Adding tools Adding activities to the place Changing attributes of the place Activities added Attribute Added

Figure 9-39 Creating the MeetingLauncher

We now create the meeting launcher that the user needs to launch a non-chat meeting. Refer to Example 9-19 on page 252 to see how we created the class with an outgoing invitation, and to Example 9-28 on page 262 for an incoming invitation. Once the MeetingLauncher constructor has been called, it passes all its parameters to the MeetingController base class constructor, as shown in Example 9-55. You can also refer to Example 9-32 on page 267 to see the MeetingController constructor once it has been called by the MeetingLauncher constructor. Actually, the MeetingController will do most of the work for the MeetingLauncher class, so most of the things we already mentioned about the MeetingController class wont be mentioned again. Refer to 9.2.4, The MeetingLauncher class on page 228 to get a general overview about this class and to Table 9-3 on page 218 for a description of event handling between the MeetingController class and the MeetingLauncher class.
Example 9-55 MeetingLauncher Constructor
MeetingLauncher::MeetingLauncher(STSession* pSTSession, const Place& place, long lActivities, long lMeetingType, bool bInitiator) :MeetingController(pSTSession,place,lActivities,lMeetingType,bInitiator) { }

Chapter 9. A complex meetings sample

285

Adding activities and attributes to the place


Creating The Place

Places Service

Joining The Place

Creating the place

Joining the place

Creating the Meeting Launcher

Creating the NwayChat Dialog

Creating the Meeting Launcher

Entering a section

Chatting Adding tools Adding activities to the place Changing attributes of the place Activities added Attribute Added

Figure 9-40 Adding activities and attributes to the place

Once we have passed both the MeetingController and the MeetingLauncher constructors, we have to wait for the PlaceListener::entered member function to be called. Once it has been called, it calls the MeetingLauncher::OnEntered member function shown in Example 9-34 on page 270 and in Example 9-56.
Example 9-56 MeetingLauncher::OnEntered member function
void MeetingLauncher::OnEntered(PlaceEvent event) { if (m_bInitiator) { PrepareTheMRC(); AddMRCActivitiesToPlace(); } }

There is also another option: we will fail entering the place. This is handled by both the MeetingController and MeetingLauncher classes, as shown in Example 9-37 on page 271 and in Example 9-57.
Example 9-57 MeetingLauncher::OnEnterFailed member function
void MeetingLauncher::OnEnterFailed(PlaceEvent event) { MeetingController::OnEnterFailed(event); delete this; }

286

Working with the Sametime Client Toolkits

As Example 9-56 shows, after checking if we are the initiators of the meeting we call the MeetingController::PrepareTheMRC and MeetingController::AddMRCActivitiesToPlace member functions to prepare the place for the meeting. Refer to Example 9-52 on page 281 to see the code which adds the activities to the place, and to Example 9-53 on page 282 to see how we change the place attributes in the MeetingController::PrepareTheMRC member function.

Waiting for attributes to be changed


Joining The Place Creating The Place

Places Service

Creating the place

Joining the place

Creating the Meeting Launcher

Creating the NwayChat Dialog

Creating the Meeting Launcher

Entering a section

Chatting Adding tools Adding activities to the place Changing attributes of the place Activities added Attribute Added

Figure 9-41 Attribute added

Once we have changed the place attribute, we wait for the AttributeChanged event. This is done in the MyPlaceListener::attributeChanged member function; once it has been called, it calls the MeetingController::OnAttributeChanged member function, as shown in Example 9-58 and Example 9-59.
Example 9-58 MyPlaceListener::attributeChanged member function
void MyPlaceListener::attributeChanged(PlaceMemberEvent event) { if (m_pCallBack) m_pCallBack->OnAttributeChanged(event); }

Example 9-59 MeetingController::OnAttributeChanged member function


void MeetingController::OnAttributeChanged(PlaceMemberEvent event) { if (event.getAttributeKey() == MEETING_REQUEST_ACTIVITIES_ID && !m_bInitiator)

Chapter 9. A complex meetings sample

287

{ STAttribute* pAttribute = event.getAttribute(); if (pAttribute) SetActivitiesFromFormattedString(pAttribute->getString().c_str()); if (m_bActivityAdded && m_pTokenService && m_pTokenServiceListener) { m_pTokenService->addTokenListener(m_pTokenServiceListener); m_pTokenService->generateToken(); } } }

As you can see in Example 9-59, we are waiting for a specific attribute ID, MEETING_REQUEST_ACTIVITIES_ID, which is the activities who were formatted into a string by the initiator of the meeting. (See Adding activities and attributes to the place on page 286.) In this way the other users who join the meeting know what activities have been added to the place. We use the MeetingController::SetActivitiesFromFormattedString member function to generate all the activities to a long type from the formatted string. This data is important when we need to create a URL that will launch the Sametime Meeting. This is discussed in more detail in Launch Sametime meeting on page 292. Once we do this, we add the token listener to the token object and generate the token, which is discussed in more detail in 9.4.3, Generating a token on page 290.

Waiting for activities to be added


Joining The Place Creating The Place

Places Service

Creating the place

Joining the place

Creating the Meeting Launcher

Creating the NwayChat Dialog

Creating the Meeting Launcher

Entering a section

Chatting Adding tools Adding activities to the place Changing attributes of the place Activities added Attribute Added

Figure 9-42 Activities added

288

Working with the Sametime Client Toolkits

Once we have added the activities to the place, we wait for the ActivitiesAdded event to occur. Once the MyPlaceListener::activityAdded member function has been called, it calls the MeetingController::OnActivityAdded member function, as you can see in Example 9-60 and Example 9-61.
Example 9-60 MyPlaceListener::activityAdded member function
void MyPlaceListener::activityAdded(PlaceEvent event) { if (m_pCallBack) m_pCallBack->OnActivityAdded(event); }

Example 9-61 MeetingController::OnActivityAdded member function


void MeetingController::OnActivityAdded(PlaceEvent event) { if (m_bActivityAdded) return; int iActivityType = event.getActivityType(); if ( (iActivityType == CHAT_MRC_MEETING_ACTIVITY) || (iActivityType != AUDIO_MRC_MEETING_ACTIVITY && iActivityType != VIDEO_MRC_MEETING_ACTIVITY && iActivityType != APPSHARE_MRC_MEETING_ACTIVITY && iActivityType != WHITEBORD_MRC_MEETING_ACTIVITY)) return; m_bActivityAdded = true; if (m_pTokenService && m_pTokenServiceListener && m_lActivities > CHAT_ACTIVITY) { m_pTokenService->addTokenListener(m_pTokenServiceListener); m_pTokenService->generateToken(); } }

There is also the possibility that our request to add activity will fail. We handle this in the MeetingController::OnAddActivityFailed member function, as you can see in Example 9-62.
Example 9-62 MeetingController::OnActivityFailed member function
void MeetingController::OnAddActivityFailed(PlaceEvent event) { long reason = event.getReason(); CString strMsg; strMsg.Format("Add Activity Failed. reason : 0x%x",reason); ::MessageBox(NULL,strMsg, "Sametime", MB_OK | MB_ICONEXCLAMATION); }

Chapter 9. A complex meetings sample

289

As you can see in Example 9-61, after checking if the activity that was added is a known activity, we add a token listener and generate a token. This step is discussed in detail in the next section.

9.4.3 Generating a token


The Token service provides the ability to generate a token that can be used by a logged-in user to log into the Sametime server without being challenged to authenticate again. For example, a Sametime application could generate a token and pass it as a parameter to a second application. The launched application would then use this token to log into the community. A token has a time limit that depends on the adminstrator configuration. In the Meetings sample, we use the Token service to generate the token and pass it to the Meeting Room Client within the URL. This is the last step before we create the URL for launching the browser and navigating to the MRC.

Generating the token


Token Service
Generate Token Generate Token
Generating Token

Token generated

Figure 9-43 Generating Token

Generating a token is very simple. All we have to do is add a TokenListener to our TokenService handler and call the TokenService::generateToken member function. As you can see in Example 9-59 on page 287, we created a new TokenListener and added it to the TokenService, and then called the TokenService::generateToken.

Token Service

Generate Token

Figure 9-44 Token generated

Now we wait for the token to be generated by the TokenService. Once this has been done, we handle this event in both MeetingLauncher and MeetingController classes. Refer to Example 9-63, Example 9-64, and Example 9-65 to see how its done.

Generate Token

Generating Token

Token generated

290

Working with the Sametime Client Toolkits

Example 9-63 MyMeetingControllerTokenServiceListener::tokenGenerated member function


void MyMeetingControllerTokenServiceListener::tokenGenerated(TokenEvent event) { if (m_pCallBack) m_pCallBack->OnTokenGenerated(event); }

Example 9-64 MeetingLauncher::OnTokenGenerated


void MeetingLauncher::OnTokenGenerated(TokenEvent event) { MeetingController::OnTokenGenerated(event); delete this; }

Example 9-65 MeetingController::OnTokenGenerated member function


void MeetingController::OnTokenGenerated(TokenEvent event) { if (m_pTokenService && m_pTokenServiceListener) m_pTokenService->removeTokenListener(m_pTokenServiceListener); CString tokenString = CString(event.getToken().getTokenString().c_str()); if (! m_lMeetingType || m_lMeetingType == ST_CHAT_MEETING) m_lMeetingType = MeetingUI::GetMeetingTypeFromActivities(m_lActivities); CString strUrl = PrepareMRCUrl(tokenString); MeetingUI::OpenMRC(m_lMeetingType, strUrl); if (m_pPlace) m_pPlace->leave(ST_OK); }

There is also the possibility that the Token Service will fail to generate the token. This event is handled also by both MeetingLauncher and MeetingController classes, as you can see in Example 9-66 and Example 9-67.
Example 9-66 MeetingLauncher::OnGenerateTokenFailed member function
void MeetingLauncher::OnGenerateTokenFailed(TokenEvent event) { MeetingController::OnGenerateTokenFailed(event); delete this; }

Chapter 9. A complex meetings sample

291

Example 9-67 MeetingController::OnGenerateTokenFailed member function


void MeetingController::OnGenerateTokenFailed(TokenEvent event) { CString strMsg; strMsg.Format("Failed to generate token. reason : 0x%x",event.getReason()); ::MessageBox(NULL,strMsg,"Sametime",MB_OK | MB_ICONEXCLAMATION); }

As you can see in Example 9-65, the first thing we do when the MeetingController::OnTokenGenerated member function has been called is remove the TokenListener from the TokenService so we wont get any events from the TokenService. Next we call the MeetingUI::GetMeetingTypeFromActivities member function so we can know what type of meeting it is going to be. This will help us open the browser window to the correct size. The third thing we do is call the MeetingController::PrepareMRCUrl and MeetingUI::OpenMRC member functions, which we discuss in more detail in the next section. The last thing we do is simply leave the place.

9.4.4 Launch Sametime meeting


Launching a Sametime meeting requires that the place has been prepared and now its ready for the meeting. The only thing left to do is just to simply go there.

Create the URL


Launch The Sametime Meeting

Sametime Meeting Services

Figure 9-45 Create the URL

There are actually two member functions we need to use to create the URL: MeetingController::PrepareMRCUrl and MeetingUI::FormatUrlCharacters. These two functions will help you create the URL you need to open the browser. Refer to Example 9-68 for the code.
Example 9-68 MeetingController::PrepareMRCURL member function
CString MeetingController::PrepareMRCUrl(CString token) {

Launch The Sametime Meeting

Create the URL

Launch the browser to open the meeting

292

Working with the Sametime Client Toolkits

CString strUrl; // Get the user name from the community MeetingUI* pMeetingUI = MeetingUI::Instance(); if (!pMeetingUI) return ""; // Build the URL strUrl = "http://"; strUrl += pMeetingUI->GetServerName(); strUrl += "/stsrc.nsf/join?OpenForm"; strUrl += "&mid="; strUrl += m_pPlace ? pMeetingUI->FormatUrlCharacters(CString(m_pPlace->getPlaceName().c_str())) : ""; strUrl += "&toktype=1&tok="; strUrl += token; strUrl += "&port="; CString sTemp; sTemp.Format("%i", SAMETIME_MEETING_SERVER_PORT); strUrl += sTemp; strUrl += "&ismgr="; strUrl += (m_bInitiator ? "1" : "0"); strUrl += "&uname="; strUrl += pMeetingUI->FormatUrlCharacters(CString(pMeetingUI->GetMyUserId().c_str())); return strUrl; }

Example 9-69 MeetingUI::FormatUrlCharacters


CString MeetingUI::FormatUrlCharacters(const CString &strInput) { CStringtmp, strRetVal(""); unsigned intcharacter; BSTR b; wchar_t* w; int length; b = strInput.AllocSysString(); w = b; length = wcslen(w); for (int i = 0; i < length; i++) { character = w[i]; if (((character >= 'A') && (character <= 'Z'))

Chapter 9. A complex meetings sample

293

|| ((character >= 'a') && (character <= 'z')) || ((character >= '0') && (character <= '9'))) { strRetVal += character; } else { tmp.Format("%c%02X%c%02X%d%c%02X", '%', '&', '%', '#', character, '%', ';'); strRetVal += tmp; } } ::SysFreeString(b); return strRetVal; }

Launch the browser to open the meeting


Launch The Sametime Meeting

Sametime Meeting Services

Figure 9-46 Launch the browser to open the meeting

Once we have created the URL, the only thing left to do is to launch the browser. We do this by calling the MeetingUI::OpenMRC static member function by passing it the meeting type and the URL, as shown in Example 9-70. As you can see in Example 9-71 and Example 9-72, the MeetingUI::OpenMRC member function will create the browser window and navigate to the URL we supplied.
Example 9-70 MeetingController::OnTokenGenerated - Calling MeetingUI::OpenMRC to open the browser window.
void MeetingController::OnTokenGenerated(TokenEvent event) { if (m_pTokenService && m_pTokenServiceListener) m_pTokenService->removeTokenListener(m_pTokenServiceListener); CString tokenString = CString(event.getToken().getTokenString().c_str()); if (! m_lMeetingType || m_lMeetingType == ST_CHAT_MEETING) m_lMeetingType = MeetingUI::GetMeetingTypeFromActivities(m_lActivities); CString strUrl = PrepareMRCUrl(tokenString); MeetingUI::OpenMRC(m_lMeetingType, strUrl);

Launch The Sametime Meeting

Create the URL Launch the browser to open the meeting

294

Working with the Sametime Client Toolkits

if (m_pPlace) m_pPlace->leave(ST_OK); }

Example 9-71 MeetingUI::OpenMRC member function - Creating the MeetingDlg(Browser) window


void MeetingUI::OpenMRC(long lMeetingType, CString strUrl) { MeetingDlg* pMeeting = new MeetingDlg(lMeetingType,strUrl); pMeeting->Create(IDD_MEETING_DLG); pMeeting->ShowWindow(SW_SHOW); pMeeting->BringWindowToTop(); }

Example 9-72 MeetingDlg::OnInitDialog member function - Navigating to the URL


BOOL MeetingDlg::OnInitDialog() { CDialog::OnInitDialog(); m_pHtmlView = new MyHtmlView; BOOL res = m_pHtmlView->Create(NULL,"MeetingBrowser",WS_CHILD | WS_VISIBLE ,CRect(5,5,40,40),this,AFX_IDW_PANE_FIRST,NULL); if (!res || ! m_pHtmlView || ! m_pHtmlView->m_hWnd) return TRUE; switch (m_lMeetingType) { case ST_AUDIO_MEETING: MoveWindow(AUDIO_MEETING_DLG_RCT); m_pHtmlView->MoveWindow(DlgRct2HtmlRct(AUDIO_MEETING_DLG_RCT)); break; case ST_VIDEO_MEETING: MoveWindow(VIDEO_MEETING_DLG_RCT); m_pHtmlView->MoveWindow(DlgRct2HtmlRct(VIDEO_MEETING_DLG_RCT)); break; case ST_SHARE_MEETING: MoveWindow(APPSHARE_MEETING_DLG_RCT); m_pHtmlView->MoveWindow(DlgRct2HtmlRct(APPSHARE_MEETING_DLG_RCT)); break; case ST_COLLABORATION_MEETING: MoveWindow(COLLABORATE_MEETING_DLG_RCT); m_pHtmlView->MoveWindow(DlgRct2HtmlRct(COLLABORATE_MEETING_DLG_RCT)); break; case ST_AV_WIZARD_MEETING: MoveWindow(AV_WIZARD_DLG_RCT); m_pHtmlView->MoveWindow(DlgRct2HtmlRct(AV_WIZARD_DLG_RCT)); break;

Chapter 9. A complex meetings sample

295

case ST_HELP: MoveWindow(HELP_DLG_RCT); m_pHtmlView->MoveWindow(DlgRct2HtmlRct(HELP_DLG_RCT)); SetWindowText("Sametime Help"); break; } m_pHtmlView->Navigate2(m_strUrl); return TRUE; }

That completes our walkthrough of the C++ Meetings sample.

9.5 Summary
In this chapter we have walked you through a full-featured Sametime C++ program. You have had the opportunity to learn a great deal about developing with C++ for Sametime. You have also been able to see how a real-world program can leverage the Sametime places architecture.

296

Working with the Sametime Client Toolkits

10

Chapter 10.

Using the C++ toolkit in Win32 programs


While the last chapter was rather long, we will be very brief in this chapter. Here we describe how to write Win32 code using the Sametime C++ toolkit. There is nothing new in the API or in the behavior of the Sametime C++ objects when writing Win32 applications using the Sametime C++ toolkit. However, there are some points you need to be aware of when writing such applications. In this chapter we focus only on the changes youll need to make when writing Win32 code compared to an MFC-based application. We will not go into detail regarding the functionality of the example, which is a very simple Sametime C++ sample.

Copyright IBM Corp. 2002. All rights reserved.

297

Win32 versus MFC: If you dont know (or dont care) what the difference is between writing Win32 and MFC code you can go right on to the next chapter.

Basically, Microsoft Foundation Classes supply the programmer with a framework that in some cases offers generalization at the cost of execution speed. Win32 does not supply any abstraction layers, which some programmers claim makes it faster than MFC. There are about 200 MFC classes, in contrast to more than 2000 Win32 API calls. The truth about the real difference between Win32 and MFC is out there somewhere, but it is not our objective to answer that question in this book. The Sametime C++ toolkit works with both, so you can use what you like.

10.1 The Win32Status sample


The Win32Status Console sample is a simple Win32 console application. This sample gets five parameters when its called: 1. 2. 3. 4. 5. Host name User name Password New status type New status description

Once this sample is called with the above parameters, it will log into the specific host-name using the user-name and password which is provided. Once it receives the loggedIn event, it will change the users-status using the parameters provided. Once the myStatusChanged event is received, the sample will log out from the server and close itself. See Figure 10-1 for an example command line.

Figure 10-1 Win32Status command line.

10.1.1 The sample code


You can see our sample code in Example 10-1.
Example 10-1 Win32Status sample code
#pragma warning(disable:4786)

298

Working with the Sametime Client Toolkits

#include #include #include #include #include #include #include #include

<windows.h> <string> "STSession.h" "CommunityService.h" "Login.h" "STUserStatus.h" "LoginListener.h" "MyStatusListener.h"

//Listeners class MyLoginListener : public LoginListener { public: virtual void loggedIn(LoginEvent event); virtual void loggedOut(LoginEvent event); }; class MyOwnStatusListener : public MyStatusListener { public: virtual void myStatusChanged(MyStatusEvent event); }; //Global Variables STSession* pSTSession; STUserStatus myUserStatus; bool bStopMessageLoop; MyOwnStatusListener* pMyStatusListener; //Main int wmain(int argc, wchar_t *argv[ ], wchar_t *envp[ ] ) { printf("starting main....\n"); if (argc < 4) { printf("Exiting with code -1 ,not enough parameters.\n"); return -1; } //Host Name wstring strHostName(argv[1]); printf("Host Name : %S\n",strHostName.c_str()); //User Name wstring strUserName(argv[2]); printf("User Name : %S\n",strUserName.c_str()); //Password wstring strPassword(argv[3]); //Status Type

Chapter 10. Using the C++ toolkit in Win32 programs

299

short sStatusType(_wtoi(argv[4])); printf("Status Type : %d\n",sStatusType); //Status Description wstring strSTatusDescription(argv[5]); printf("Status Description: %S\n",strSTatusDescription.c_str()); //Set myUserStatus object printf("Setting myUserStatus object.....\n"); myUserStatus.setStatusType(sStatusType); myUserStatus.setStatusDescription(strSTatusDescription); printf("myUserStatus object was set.\n"); //Start Session printf("Creating new STSession.....\n"); pSTSession = new STSession(L"Win32STatus"); printf("STSession* created : 0x%X\n",(long)pSTSession); printf("Stating the STSession.....\n"); pSTSession->start(); printf("STSession started.\n"); //Creating new CommunityServive printf("Creating new CommunityService.....\n"); CommunityService* pCommunityService = NULL; pCommunityService = new CommunityService(pSTSession); printf("CommunityService* created : 0x%X\n",(long)pCommunityService); //Creating new MyLoginListener printf("Creating new MyLoginListener.....\n"); MyLoginListener* pLoginListener = NULL; pLoginListener = new MyLoginListener; printf("MyLoginListener* created : 0x%X\n",(long)pLoginListener); //Adding MyLoginListener printf("Adding MyLoginListener to the CommunityService.....\n"); pCommunityService->addLoginListener(pLoginListener); printf("MyLoginListener* Added.\n"); //Message Loop printf("Stating Message Loop......\n"); MSG msg; bool bFirstLoop = true; bStopMessageLoop = false; while(GetMessage(&msg,NULL,0,0) && !bStopMessageLoop) { if (bFirstLoop) { //Login To Sametime printf ("Loging to Sametime.....\n");

300

Working with the Sametime Client Toolkits

if (pCommunityService) pCommunityService->loginByPassword(strHostName,strUserName,strPassword); bFirstLoop = false; } DispatchMessage(&msg); } printf("Message Loop Stoped.\n"); //Remove MyLoginListener printf ("Removing MyloginListener from CommunityService.....\n"); if (pCommunityService && pLoginListener) pCommunityService->removeLoginListener(pLoginListener); printf ("MyloginListener Removed.\n"); //Delete MyloginListener printf ("Deleting MyloginListener.....\n"); if (pLoginListener) delete pLoginListener; pLoginListener = NULL; printf ("MyloginListener* Deleted : 0x%X.\n",(long)pLoginListener); //Stopping the Session printf("Stopping the STSession.....\n"); if (pSTSession) pSTSession->stop(); printf("STSession Stopped.\n"); //Deleting the Session printf("Deleting the STSession.....\n"); if (pSTSession) delete pSTSession; printf("STSession* Deleted : 0x%X.\n",(long)pSTSession); //Exit printf("Exiting with code 0"); return 0; } void MyLoginListener::loggedIn (LoginEvent event) { printf("loggedIn event has been called\n"); //Getting Community Service object printf("Getting the CommunityService object.....\n"); CommunityService* pCommunityService = NULL; if (pSTSession) pCommunityService = (CommunityService*) (pSTSession->getComponent(COMMUNITY_COMP_NAME)); printf("CommunityService* : 0x%X\n",(long)pCommunityService);

Chapter 10. Using the C++ toolkit in Win32 programs

301

//Getting Login object printf("Getting the Login object.....\n"); Login* pLogin = NULL; if (pCommunityService) pLogin = pCommunityService->getLogin(); printf("Login* : 0x%X\n",(long)pLogin); //Creating new MyOwnStatusListener printf("Creating new MyOwnStatusListener.....\n"); pMyStatusListener = NULL; pMyStatusListener = new MyOwnStatusListener; printf("MyOwnStatusListener* created : 0x%X\n", (long)pMyStatusListener); //Adding MyLoginListener printf("Adding MyOwnStatusListener to the Login.....\n"); pLogin->addMyStatusListener(pMyStatusListener); printf("MyOwnStatusListener* Added.\n"); //Change the Status printf("Changing the status.....\n"); if (pLogin) pLogin->changeMyStatus(myUserStatus); } void MyLoginListener::loggedOut(LoginEvent event) { printf("loggedOut event has been called. reason : 0x%X\n", event.getReason()); bStopMessageLoop = true; } void MyOwnStatusListener::myStatusChanged(MyStatusEvent event) { printf("myStatusChanged event has been called.\n\t\tStatus Type : %d\n\t\tStatus Description : %S\n", event.getStatus().getStatusType(), event.getStatus().getStatusDescription().c_str()); //Getting Community Service object printf("Getting the CommunityService object.....\n"); CommunityService* pCommunityService = NULL; if (pSTSession) pCommunityService = (CommunityService*) (pSTSession->getComponent(COMMUNITY_COMP_NAME)); printf("CommunityService* : 0x%X\n",(long)pCommunityService); //Logging out from Sametime

302

Working with the Sametime Client Toolkits

printf("Logging out from Sametime.....\n"); if (pCommunityService) pCommunityService->logout(); }

10.1.2 The output window


Figure 10-2 shows output from the Win32Status sample.

Figure 10-2 Win32Status.exe output window

Chapter 10. Using the C++ toolkit in Win32 programs

303

As we said, this is a very simple program, but enough to illustrate the differences between programming for MFC and Win32.

10.2 Writing Win32 code with Sametime C++ toolkit


In this section we discuss things you must consider when you are writing Win32 code with the Sametime C++ toolkit.

10.2.1 Libraries
The only difference between MFC applications and Win32 applications is that in MFC applications you link with the starchmfc.lib library and for Win32 application you should link with the starch.lib. Set your project settings to use the starch.lib if you write a Win32 application. All other Sametime libraries can be used for both MFC and win32 applications.

10.2.2 Using wmain


Sametime C++ toolkit uses and supports wide-characters. wmain is the wide-character version of main. As you can see in Example 10-1 on page 298, we use wmain and wchar_t* when we get argv and envp parameters. This is useful when we want to use these parameters with wide-characters strings like wstring.

10.2.3 The message loop


When you write Win32 code using the Sametime C++ toolkit, your code must have a message-loop. Message-loop enables your application to receive messages sent to it by the operating system (usually needed for socket messages). Example 10-2 shows you how a basic message loop should be.
Example 10-2 The Message-Loop
MSG msg; while(GetMessage(&msg,NULL,0,0)) DispatchMessage(&msg);

You can put the message-loop anywhere in your application. Refer to Example 10-1 on page 298 to see where we put it in our Win32Status sample.

304

Working with the Sametime Client Toolkits

Important: Without Message-Loop in your Win32 application, you will not be able to get any response from the C++ Toolkit Services and objects.

This concludes our discussion of Win32 coding considerations when using the Sametime C++ toolkit.

10.3 Summary
In this chapter we showed you how to write a very simple Win32 program with the Sametime C++ toolkit. If you want to use the Sametime C++ toolkit in a Win32 program, you must link with a library other than the one used with MFC. If your program must support wide characters, you must use the wmain function. And finally, make sure your Win32 program has a message loop. Otherwise it will not be able to receive the events that the full Sametime architecture is based upon.

Chapter 10. Using the C++ toolkit in Win32 programs

305

306

Working with the Sametime Client Toolkits

Part 4

Part

COM and Sametime Links toolkits

Copyright IBM Corp. 2002. All rights reserved.

307

308

Working with the Sametime Client Toolkits

11

Chapter 11.

The COM toolkit


This chapter is about one of the newest members of the Sametime toolkit family: Sametime COM toolkit. We start with an overview of the toolkit, how you get it, and how you set up Visual Basic to use it. In the remainder of the chapter we will cover the capabilities of the toolkit in one big sample that we call BuddyList. We develop the sample in steps, starting with the basic capabilities of logging in and out from the Sametime server. We then add functionality to the sample in two more steps until we have the final BuddyList sample.

Copyright IBM Corp. 2002. All rights reserved.

309

11.1 Overview
The Sametime COM toolkit provides the basic Sametime community services, delivered as a standard DLL with interfaces that represent the services provided. This toolkit can be used to enable applications with Sametime in any development environment that supports COM, such as Visual Basic/VBA (used in Microsoft Office and other applications), and JavaScript in Microsoft Internet Explorer. The COM Toolkit provides the basic functionality required to develop a Sametime application. The COM Toolkit supports Automation OLE, and is delivered as a DLL file. A tlb file is provided as well, to support importing of all the interface names. Using the development tools with which you are familiar, you can write your own user interface on top of the Sametime services. Figure 11-1 shows a sample application, Buddy List, written using the COM Toolkit.

Figure 11-1 Sample Sametime Buddy List application

310

Working with the Sametime Client Toolkits

The Sametime COM toolkit exposes the following subset of the Sametime community services, described in the following sections: Community service Lookup service Awareness service Instant messaging service

Community service
The Community service is the core service you must use to log in and log out from the Sametime server. In addition to login, the Community service provides the ability to change your online status, to receive administrator messages, and to request to change your displayed user name if you logged on anonymously.

Lookup service
The Lookup service provides the ability to resolve user names to unique user objects, for example, when adding a user to the buddy list.

Awareness service
The Awareness service provides the ability to be aware of the online status of Sametime users. Using this service, you can register to receive notifications of changes in the online status of users. This service is sometimes referred to as People Awareness.

Instant messaging service


The Instant messaging service allows the sending of text and binary messages between clients. It is used for standard instant messages, but can also be used for passing any other messages, such as game moves and translated messages.

Chapter 11. The COM toolkit

311

11.2 Getting started


We now look at how you get the COM toolkit and how you add the toolkit reference to Visual Basic.

11.2.1 Accessing the toolkit


To access the pages that include the documentation, samples, and Toolkit, follow these steps: 1. Navigate to the home page of your Sametime 3.x server.
http://<your_sametime_server_name

2. Click the Toolkit link at the bottom of the page. You might need to scroll down the page to see the link. 3. Click COM Toolkit on the Toolkits page. You are now at the Sametime COM toolkit home page, as shown in Figure 11-2 on page 313.

312

Working with the Sametime Client Toolkits

Figure 11-2 The COMToolkit Homepage

11.2.2 Installing the toolkit


You can download and install the COM Toolkit by clicking the Toolkit & Samples link on the COM Toolkit home page.

11.2.3 Adding the COM toolkit reference to your project


You can use the COM Toolkit in two ways: early binding and late binding. When you use the early binding method, youll need to add a library reference to your project. To add the COM Toolkit reference to your project click the Project -> References menu item, as illustrated in Figure 11-3 on page 314.

Chapter 11. The COM toolkit

313

Figure 11-3 Adding COM Toolkit reference to your project : Click References menu item.

After clicking the Reference menu item, the References dialog is opened. Once the dialog is opened, search for STComTk.dll and select it. Then click OK , as shown in Figure 11-4 on page 315.

314

Working with the Sametime Client Toolkits

Figure 11-4 Adding COM toolkit reference to your project: References Dialog

You can also use the late binding method. To use this youll need the STComTkLib library.

11.3 Visual Basic samples


This section shows how to build the BuddyList sample step-by-step. We will go through: Logging in Adding awareness and status capabilities The complete Buddy List, including Instant Messaging You can use these samples to understand the toolkit API, and modify them for use in your own applications. Refer to the Sametime COM toolkit Developers Guide for additional information as you read this section.

Chapter 11. The COM toolkit

315

11.4 The Login sample


The Login sample is a simple Visual Basic sample. It demonstrates the ease of getting connected to a Sametime server using the Community service. You can see the user interface elements of the finished sample in Figure 11-5.

Figure 11-5 Login sample

As mentioned earlier, the first thing we need to do after creating a new project in Visual Basic is reference the Sametime COM toolkit to the project. See 11.2.3, Adding the COM toolkit reference to your project on page 313 for details.

11.4.1 Initialize Sametime services - the SametimeSession module


The SametimeSession module is used for initializing all the Sametime services that are needed for the sample. All services will be stored as private members of the module and will be initialized in the InitializeSession public method. All service can be accessed by using the Get<ServiceName> public function. This function will return a reference to the service.
Example 11-1 Login Sample - SametimeSession Module
Private MyCommunityService As CommunityService Public Sub InitializeSession() Set MyCommunityService = New CommunityService End Sub Public Function GetCommunityService() As CommunityService Set GetCommunityService = MyCommunityService End Function

316

Working with the Sametime Client Toolkits

Services
The Login sample will need only the login\logout functionality, so the only service we need is the CommunityService. This service will be held as a private member of the module. To retrieve the CommunityService service from the module, we will provide a public function GetCommunityService which will return its private member MyCommunityServiceas seen in Example 11-2.
Example 11-2 SametimeSession_GetCommunityService Public Function
Private MyCommunityService As CommunityService . . . Public Function GetCommunityService() As CommunityService Set GetCommunityService = MyCommunityService End Function

Initializing
The SametimeSession module provides a public method to initialize all its services. Usually we initialize all the services when the application is loaded. In this sample, and in all the other samples, we will do this when the Form_Load event of the main form is fired. We create and initialize all services by using the New keyword, as seen in Example 11-3 in the InitilizeSession public method.
Example 11-3 SametimeSession_InitializeSession Public Method
Public Sub InitializeSession() Set MyCommunityService = New CommunityService End Sub

11.4.2 Login to Sametime - the LoginForm


The LoginForm is used to give us the ability to get the Host Name (or server name), User Name, and Password from the user. These parameters are necessary when we want to login to Sametime.

Chapter 11. The COM toolkit

317

Figure 11-6 LoginForm

In this sample, the LoginForm shown in Figure 11-6 will be used as the main form of the application and will be the first one to be loaded.
Example 11-4 LoginForm Code
Private WithEvents MyCommunityService As CommunityService Private Sub Form_Load() SametimeSession.InitializeSession Set MyCommunityService = SametimeSession.GetCommunityService End Sub Private Sub Login_Click() MyCommunityService.LoginByPassword Host, UserName, Password End Sub Private Sub MyCommunityService_LoggedIn(ByVal ev As STComTkLib.ILoginEvent) MsgBox "You are logged in to sametime." Login.Caption = "Logout" End Sub Private Sub MyCommunityService_LoggedOut(ByVal ev As STComTkLib.ILoginEvent) MsgBox "You have been logged out." & vbNewLine & _ "Reason : 0x" & Hex(ev.Reason) Login.Caption = "Login" End Sub

Private members
We will declare one private member which is the CommunityService, so we can use it to log into Sametime. This member will be declared with events so we can get the LoggedIn/loggedOut events, as shown in Example 11-5.

318

Working with the Sametime Client Toolkits

Example 11-5 LoginForm Private Members


Private WithEvents MyCommunityService As CommunityService

Form_Load event
Once the Application is started, the Form_Load event is fired because this is the application main form.
Example 11-6 LoginForm_FormLoad event
Private Sub Form_Load() SametimeSession.InitializeSession Set MyCommunityService = SametimeSession.GetCommunityService End Sub

As seen in Example 11-6, after calling SametimeSession.InitializeSession we set the private member MyCommunityService to CommunityService, which was already initialized in the SametimeSession, by using SametimeSession.GetCommunityService public method.

Login_Click event
Once the user clicks the Login button, the Login_Click event is fired. Using the HostName, UserName, and Password edit fields, we will try to log into Sametime by calling the MyCommunityService.LoginByPassword function, as shown in Example 11-7.
Example 11-7 LoginForm_Login_Click event
Private Sub Login_Click() MyCommunityService.LoginByPassword Host, UserName, Password End Sub

After calling the MyCommunityService.LoginByPassword function, we wait for one of these events: LoggedIn or LoggedOut.

MyCommunityService_LoggedIn event
Once we have successfully logged into Sametime, the MyCommunityService_LoggedIn event will be fired. In this sample we will create a message box which will identify it, as shown in Example 11-8.
Example 11-8 LoginForm_MyCommunityService_LoggedIn event
Private Sub MyCommunityService_LoggedIn(ByVal ev As STComTkLib.ILoginEvent) MsgBox "You are logged in to sametime." End Sub

Chapter 11. The COM toolkit

319

MyCommunityService_LoggedOut event
Once we have failed to log into Sametime, the MyCommunityService_LoggedOut event is fired. Using the LoginEvent which is provided once the event is fired, we can get the reason for the failed login. Refer to the COM Toolkit Reference Guide for more details about errors using the ISTError enum.
Example 11-9 LoginForm_MyCommunityService_LoggedOut event
Private Sub MyCommunityService_LoggedOut(ByVal ev As STComTkLib.ILoginEvent) MsgBox "You have been logged out." & vbNewLine & _ "Reason : 0x" & Hex(ev.Reason) End Sub

As seen in Example 11-9, we create a message box once the MyCommunityService_LoggedOut event is fired and provide it the reason code as we get it from the LoginEvent.

11.5 The Awareness sample


The Awareness sample adds to the Login sample the ability to be aware of the status of other users. This sample uses the LookupService to resolve names of Sametime users and add them to the Awareness List, and uses the AwarenessService to be aware of other users status. This sample continues from where the Login sample stopped. Using this sample, we are able to log into Sametime, add users to the AwarenessList, and view their status. We will also add two additional features: the ability to change our own status, and the ability to get messages from the server administrator. Both are implemented using the CommunityService.

320

Working with the Sametime Client Toolkits

Figure 11-7 Awareness sample

11.5.1 Initialize Sametime service - the SametimeSession module


We will extend the Login sample SametimeSession module by adding some additional services to it during the initialization.
Example 11-10 Awareness SametimeSession Code
Private MyCommunityService As CommunityService Private MyLookupService As LookupService Private MyAwarenessService As AwarenessService Public Sub InitializeSession() Set MyCommunityService = New CommunityService Set MyLookupService = New LookupService Set MyAwarenessService = New AwarenessService End Sub Public Function GetCommunityService() As CommunityService

Chapter 11. The COM toolkit

321

Set GetCommunityService = MyCommunityService End Function Public Function GetLookupService() As LookupService Set GetLookupService = MyLookupService End Function Public Function GetAwarenessServie() As AwarenessService Set GetAwarenessServie = MyAwarenessService End Function

Services
We add the LookupService and AwarenessService private members to the SametimeSession Module, which already has the CommunityService private member we added in the Login sample. See Example 11-11.
Example 11-11 SametimeSession Private Members
Private MyCommunityService As CommunityService Private MyLookupService As LookupService Private MyAwarenessService As AwarenessService

We also provide public functions to retrieve these services, as you can see in Example 11-12.
Example 11-12 SametimeSession Access to the services
Public Function GetCommunityService() As CommunityService Set GetCommunityService = MyCommunityService End Function Public Function GetLookupService() As LookupService Set GetLookupService = MyLookupService End Function Public Function GetAwarenessServie() As AwarenessService Set GetAwarenessServie = MyAwarenessService End Function

Initializing
We must initialize the new private members that we added, as shown in Example 11-13.
Example 11-13 Awareness SametimeSession_InitializeSession public method
Public Sub InitializeSession() Set MyCommunityService = New CommunityService Set MyLookupService = New LookupService

322

Working with the Sametime Client Toolkits

Set MyAwarenessService = New AwarenessService End Sub

11.5.2 Be aware of other users - the AwarenessForm


The AwarenessForm is the main form of the application. You can see the form in Figure 11-8. This form holds one ListView control (AwarenessList) and provides us the ability to add ListItems, which are the Sametime users. This form also includes an ImageList control (AwarenessImageList), which provides the AwarenessList with all of its icons. This form holds three buttons: Login/Logout, AddUser, and ChangeStatus. This form handles all its buttons Click events.

Figure 11-8 AwarenessForm

The code for the AwarenessForm is shown in Example 11-14.


Example 11-14 AwarenessForm Code
Private WithEvents MyCommunityService As CommunityService Private WithEvents MyAwarenessService As AwarenessService Private WithEvents MyWatchList As WatchList

Chapter 11. The COM toolkit

323

Public Sub AddUserToList(ByRef User As STUser) If Not IsNull(MyWatchList) Then MyWatchList.AddUser User AwarenessListView.ListItems.Add 1, User.Id.Id, User.Name End If End Sub Private Sub ChangeStatus_Click() Dim MyChangeStatusForm As New ChangeStatusForm MyChangeStatusForm.Left = Me.Left + Me.Width MyChangeStatusForm.Top = Me.Top MyChangeStatusForm.Show vbModeless, Me End Sub Private Sub Form_Load() SametimeSession.InitializeSession Set MyCommunityService = SametimeSession.GetCommunityService Set MyAwarenessService = SametimeSession.GetAwarenessServie End Sub Private Sub Login_Click() If MyCommunityService.IsLoggedIn Then MyCommunityService.LogOut Else Dim MyLoginForm As New LoginForm MyLoginForm.Left = Me.Left + Me.Width MyLoginForm.Top = Me.Top MyLoginForm.Show vbModeless, Me End If End Sub Private Sub AddUser_Click() If MyCommunityService.IsLoggedIn Then Dim MyAddUserForm As AddUserForm Set MyAddUserForm = New AddUserForm MyAddUserForm.Left = Me.Left + Me.Width MyAddUserForm.Top = Me.Top MyAddUserForm.SetAwarenessForm Me MyAddUserForm.Show vbModeless, Me End If End Sub Private Sub MyCommunityService_AdminMsgReceived(ByVal ev As STComTkLib.IAdminMsgEvent) MsgBox ev.MsgText, vbInformation, "Admin Message" End Sub Private Sub MyCommunityService_LoggedIn(ByVal ev As STComTkLib.ILoginEvent)

324

Working with the Sametime Client Toolkits

Login.Caption = "Logout" AddUser.Enabled = True ChangeStatus.Enabled = True End Sub Private Sub MyCommunityService_LoggedOut(ByVal ev As STComTkLib.ILoginEvent) Login.Caption = "Login" AddUser.Enabled = False ChangeStatus.Enabled = False End Sub Private Sub MyAwarenessService_ServiceAvailable(ByVal ev As STComTkLib.IAwarenessServiceEvent) Set MyWatchList = MyAwarenessService.CreateWatchList AwarenessListView.Enabled = True End Sub Private Sub MyAwarenessService_ServiceUnavailable(ByVal ev As STComTkLib.IAwarenessServiceEvent) If Not IsNull(MyWatchList) Then MyWatchList.Reset Set MyWatchList = Nothing End If AwarenessListView.ListItems.Clear AwarenessListView.Enabled = False End Sub Private Sub MyWatchList_UserStatusChanged(ByVal ev As STComTkLib.IStatusEvent) Dim IconNumber As Integer Dim Item As ListItem Set Item = FindUserInList(ev.WatchedUser.Id) If Item.Index > 0 Then Select Case ev.WatchedUser.Status.StatusType Case IST_USER_STATUS_ACTIVE IconNumber = 1 Case IST_USER_STATUS_AWAY IconNumber = 2 Case IST_USER_STATUS_DND IconNumber = 3 Case Else IconNumber = 0 End Select Dim Index As Integer Dim Key, Text As String Index = Item.Index Key = Item.Key Text = Item.Text AwarenessListView.ListItems.Remove Item.Index

Chapter 11. The COM toolkit

325

AwarenessListView.ListItems.Add Index, Key, Text, IconNumber, IconNumber AwarenessListView.Refresh End If End Sub Private Function FindUserInList(ByRef UserId As STId) As ListItem Dim Item As ListItem For Each Item In AwarenessListView.ListItems If Item.Key = UserId.Id Then Set FindUserInList = Item End If Next Item End Function

Private members
The AwarenessForm holds the following private members: CommunityService - So we know when the user is logged in\logged out, and to get administrator messages. AwarenessService - So we know whether the Awareness service is available or not. WatchList - Created by the AwarenessService when we get the ServiceAvailable event; it is used for getting events on users status. As shown in Example 11-15, all members are declared with the WithEvents keyword so we can get all the events from our members.
Example 11-15 AwarenessForm Private Members
Private WithEvents MyCommunityService As CommunityService Private WithEvents MyAwarenessService As AwarenessService Private WithEvents MyWatchList As WatchList

Form_Load event
When the application is started and because AwarenessForm is the application main form, Form_Load event is being fired. This is a good place in your code to initialize the SametimeSession and the private members of the form. See Example 11-16. First we initialize the SametimeSession module, as we did in the Login sample, and then we set all our private members to be referenced to the ones in the SametimeSession.
Example 11-16 AwarenessForm - Form_Load event
Private Sub Form_Load() SametimeSession.InitializeSession

326

Working with the Sametime Client Toolkits

Set MyCommunityService = SametimeSession.GetCommunityService Set MyAwarenessService = SametimeSession.GetAwarenessServie End Sub

Login_Click event
When the user clicks the Login button, the Login_Click event is fired. See Example 11-17. Because the Login button is used also for Logout, when we log into Sametime the first thing we do is to check if we are currently logged in. If we are currently logged in it means that the user wants to log out of Sametime, so we log out. Otherwise we need to create the LoginForm to do the login.
Example 11-17 AwarenessForm - Login_Click event
Private Sub Login_Click() If MyCommunityService.IsLoggedIn Then MyCommunityService.LogOut Else Dim MyLoginForm As New LoginForm MyLoginForm.Left = Me.Left + Me.Width MyLoginForm.Top = Me.Top MyLoginForm.Show vbModeless, Me End If End Sub

You can refer to Log into Sametime - the LoginForm on page 332 for more details about the LoginForm.

MyCommunityService_LoggedIn event
Once we have successfully logged into Sametime, the MyCommunityService_ LoggedIn event is fired. As seen in Example 11-18, the first thing we do is change the Login button caption to Logout, so when the user decides to logout from the server he can press this button. Second, we enable both AddUser and ChangeStatus buttons because now the user can use them.
Note: You can resolve users and change your status only when you are logged into Sametime. If you do this when you are offline, these changes will not take any effect in the Sametime server.
Example 11-18 AwarenessForm - MyCommunityService_LoggedIn event
Private Sub MyCommunityService_LoggedIn(ByVal ev As STComTkLib.ILoginEvent) Login.Caption = "Logout" AddUser.Enabled = True

Chapter 11. The COM toolkit

327

ChangeStatus.Enabled = True End Sub

MyCommunityService_LoggedOut event
If we have failed to log into Sametime, the MyCommunityService_LoggedOut event is fired. See Example 11-19. First we change the Login button caption to Login so the user can try to login again by pressing this button. Next, we disable both AddUser and ChangeStatus buttons because now the user is offline and cant use these buttons.
Example 11-19 AwarenessForm - MyCommunityService_LoggedOut event
Private Sub MyCommunityService_LoggedOut(ByVal ev As STComTkLib.ILoginEvent) Login.Caption = "Login" AddUser.Enabled = False ChangeStatus.Enabled = False End Sub

MyCommunityService_AdminMsgReceived event
Accepting administrator messages is possible if we listen to the MyCommunityService_AdminMsgReceived event. Once the MyCommunityService_AdminMsgReceived event is fired, we can access the message which was sent from the administrator by using the AdminMsgEvent.MsgEvent property from the AdminMsgEvent object, as seen in Example 11-20.
Example 11-20 AwarenessForm - MyCommunityService_AdminMsgReceived event
Private Sub MyCommunityService_AdminMsgReceived(ByVal ev As STComTkLib.IAdminMsgEvent) MsgBox ev.MsgText, vbInformation, "Admin Message" End Sub

Attention: All properties in Sametime events are read only. You wont be able to change them.

MyAwarenessService_ServiceAvailable event
This event will be fired once we have successfully logged into Sametime or when we are already logged into Sametime and the AwarenessService on the server goes down and comes up again.

328

Working with the Sametime Client Toolkits

See Example 11-21. When the MyAwarenessService_ServiceAvailable event is fired, the first thing we do is create a new WatchList object by using the MyAwarenessService.CreateWatchlist function.
Example 11-21 AwarenessForm - MyAwarenessService_ServiceAvailable event
Private Sub MyAwarenessService_ServiceAvailable(ByVal ev As STComTkLib.IAwarenessServiceEvent) Set MyWatchList = MyAwarenessService.CreateWatchList AwarenessListView.Enabled = True End Sub

For more information about the WatchList Interface refer to the Sametime COM Toolkit User Guide that is delivered as a PDF file together with the toolkit.

MyAwarenessService_ServiceUnavailable event
This event is fired once we have logged out from Sametime from any reason and also when the AwarenessService on the server went down. You can see in Example 11-22 how we handle the MyAwarenessService_ServiceUnavailable event. We reset the MyWatchList object by calling the MyWatchlist.Reset function and then reference it to Nothing. After this we clear the AwarenessListView control and disable it.
Note: Once the Awareness Service is unavailable, all WatchList objects are disabled, so you wont get any event while the service is down.
Example 11-22 AwarenessForm - MyAwarenessService_ServiceUnavailable event
Private Sub MyAwarenessService_ServiceUnavailable(ByVal ev As STComTkLib.IAwarenessServiceEvent) If Not IsNull(MyWatchList) Then MyWatchList.Reset Set MyWatchList = Nothing End If AwarenessListView.ListItems.Clear AwarenessListView.Enabled = False

AddUser_Click event
When the user decides that he wants to add a new user to his AwarenessList, he presses the AddUser button. Once the AddUser button is pressed, the AddUser_Click event is fired.
Example 11-23 AwarenessForm - AddUser_Click event
Private Sub AddUser_Click()

Chapter 11. The COM toolkit

329

If MyCommunityService.IsLoggedIn Then Dim MyAddUserForm As AddUserForm Set MyAddUserForm = New AddUserForm MyAddUserForm.Left = Me.Left + Me.Width MyAddUserForm.Top = Me.Top MyAddUserForm.SetAwarenessForm Me MyAddUserForm.Show vbModeless, Me End If End Sub

See Example 11-23. We check whether we are currently logged into the server, and if so, we create a new AddUserForm, which will do all the resolving work with the LookupService. For more information about the AddUserForm, refer to Adding users to the AwarenessList - the AddUserForm on page 335.

AddUserToList public method


This public method is called by the AddUserForm when the resolving process is complete; the STUser object we get represents the user we wanted to add to the AwarenessList. See Example 11-24. When the AddUserToList public method is called, the first thing we do after we check whether MyWatchList object is valid is add the STUser object we got from the AddUserForm to the MyWatchList object. By adding users to the WatchList we are able to get events on their status changes.
Note: Once you have added a user to your WatchList object, you will automatically receive a status event on the user to identify its current status.

The second thing we do is add the user to the AwarenessListView control by calling the AwarenessListView.ListItems.Add function and providing it with the UserId property as a unique key and the User.Name as the string which represents the user name.
Example 11-24 AwarenessForm - AddUsertoList Public Method
Public Sub AddUserToList(ByRef User As STUser) If Not IsNull(MyWatchList) Then MyWatchList.AddUser User AwarenessListView.ListItems.Add 1, User.Id.Id, User.Name End If End Sub

330

Working with the Sametime Client Toolkits

MyWatchList_UserStatusChanged event
The UserStatusChanged event is fired once a user has changed his own status or once a new user is added to the WatchList object.
Example 11-25 Awareness Form - MyWatchList_UserStatusChanged event
Private Sub MyWatchList_UserStatusChanged(ByVal ev As STComTkLib.IStatusEvent) Dim IconNumber As Integer Dim Item As ListItem Set Item = FindUserInList(ev.WatchedUser.Id) If Item.Index > 0 Then Select Case ev.WatchedUser.Status.StatusType Case IST_USER_STATUS_ACTIVE IconNumber = 1 Case IST_USER_STATUS_AWAY IconNumber = 2 Case IST_USER_STATUS_DND IconNumber = 3 Case Else IconNumber = 0 End Select Dim Index As Integer Dim Key, Text As String Index = Item.Index Key = Item.Key Text = Item.Text AwarenessListView.ListItems.Remove Item.Index AwarenessListView.ListItems.Add Index, Key, Text, IconNumber, IconNumber AwarenessListView.Refresh End If End Sub

As you see in Example 11-25, once MyWatchList_UserStatusChanged event is fired the following steps are taken: 1. Try to find if the user exists in the AwarenessListView. 2. Check the user new status by using the ev.WatchedUser.Status.StatusType property, and attach to it new icon which identifies its new status. 3. Replace the old ListItem with the updated one so the status changes will be reflected on the AwarenessListView control. Refer to the Sametime COM Toolkit User Guide for more information about StatusEvent and STWatchedUser interfaces. This guide is delivered together with the toolkit as a PDF file.

Chapter 11. The COM toolkit

331

FindUserInList private function


The FindUserInList private function goes through AwarenessListView items collection and tries to find an item with a unique key that is equal to the UserId.Id property. If this function finds the item, the item is returned, as shown in Example 11-26.
Example 11-26 AwarenessForm - FindUserInList Private Function
Private Function FindUserInList(ByRef UserId As STId) As ListItem Dim Item As ListItem For Each Item In AwarenessListView.ListItems If Item.Key = UserId.Id Then Set FindUserInList = Item End If Next Item End Function

ChangeStatus_Click event
A user can change online status by clicking on the ChangeStatus button. Once the user clicks on the ChangeStatus button, the ChangeStatus_Click event is fired, as shown in Example 11-27. We create a new ChangeStatusForm and place it on the right corner of the AwarenessForm.
Example 11-27 AwarenessForm - ChangeStatus_Click event
Private Sub ChangeStatus_Click() Dim MyChangeStatusForm As New ChangeStatusForm MyChangeStatusForm.Left = Me.Left + Me.Width MyChangeStatusForm.Top = Me.Top MyChangeStatusForm.Show vbModeless, Me End Sub

For more information about the ChangeStatusForm, refer to Changing my own status - the ChangeStatusForm on page 338.

11.5.3 Log into Sametime - the LoginForm


The LoginForm does all the login work for the Awareness application. The LoginForm replaces the LoginForm from the Login sample. This form now is launched when the user clicks the Login button on the AwarenessForm. While it still looks like the login form in Figure 11-6 on page 318, there are some code changes in the Login sample, as seen in Example 11-28.

332

Working with the Sametime Client Toolkits

Example 11-28 LoginForm Code


Private WithEvents MyCommunityService As CommunityService Private Sub Form_Load() Set MyCommunityService = SametimeSession.GetCommunityService End Sub Private Sub Login_Click() MyCommunityService.LoginByPassword Host, UserName, Password End Sub Private Sub MyCommunityService_LoggedIn(ByVal ev As STComTkLib.ILoginEvent) Unload Me End Sub Private Sub MyCommunityService_LoggedOut(ByVal ev As STComTkLib.ILoginEvent) MsgBox "You have been logged out." & vbNewLine & _ "Reason : 0x" & Hex(ev.Reason) End Sub

Private members
The LoginForm holds only one private member, the CommunitySevice. We declare the MyCommunityService as a CommunityService and use the WithEvents keyword to be able to get the LoggedIn\Loggedout events as seen in Example 11-29.
Example 11-29 LoginForm Private Members
Private WithEvents MyCommunityService As CommunityService

Form_Load event
When the user clicks the Login button on the AwarenessForm, the new LoginForm is created. Once a new LoginForm is created, the Form_Load Event is fired.
Example 11-30 LoginForm - Form_Load event
Private Sub Form_Load() Set MyCommunityService = SametimeSession.GetCommunityService End Sub

As seen in Example 11-30, once the Form_Load event is fired we reference the MyCommunityService private member to the CommunityService member in the SametimeSession module.

Chapter 11. The COM toolkit

333

Login_Click event
When the user has entered all the necessary parameters in the LoginForm and clicked the Login button, the Login_Click event is fired. As seen in Example 11-31, once the Login_Click event is fired we call the MyCommunityService.LoginByPassword function with the HostName, UserName, and password text fields text.
Example 11-31 LoginForm - Login_Click
Private Sub Login_Click() MyCommunityService.LoginByPassword Host, UserName, Password End Sub

MyCommunityService_LoggedIn event
Once we have successfully logged into Sametime, this form has finished its work and can be closed (AwarenessForm will also get the event from the CommunityService and will handle this event), as seen in Example 11-32.
Example 11-32 LoginForm - MyCommunityService_LoggedIn event
Private Sub MyCommunityService_LoggedOut(ByVal ev As STComTkLib.ILoginEvent) MsgBox "You have been logged out." & vbNewLine & _ "Reason : 0x" & Hex(ev.Reason) End Sub

Tip: You can reference as many Sametime objects as you like to get Sametime events. All events in the referenced objects will be fired. This is useful when you want to get the same event in different forms, modules, or classes.

MyCommunityService_LoggedOut event
If the login to Sametime fails, the MyCommunityService_LoggedOut event is fired. Using the LoginEvent which is provided once the event is fired, we can get the reason for the failed login. Refer to the COM Toolkit Reference Guide for more details about errors using the ISTError enum.
Example 11-33 LoginForm - MyCommunityService_LoggedOut event
Private Sub MyCommunityService_LoggedOut(ByVal ev As STComTkLib.ILoginEvent) MsgBox "You have been logged out." & vbNewLine & _ "Reason : 0x" & Hex(ev.Reason) End Sub

334

Working with the Sametime Client Toolkits

As seen in Example 11-9, we create a message box if the MyCommunityService_LoggedOut event is fired and provide it with the reason code that we get from the LoginEvent. At this point the form will not be closed. The message box appears and notifies the user of the reason for the login failure. It also gives another chance to correct the login parameters.

11.5.4 Adding users to the AwarenessList - the AddUserForm


We now add an AddUserForm to use for resolving a user name provided by the user into a Sametime STUser interface. You can see how the form looks in Figure 11-9.

Figure 11-9 AddUserForm

If the resolving process succeeds, it calls the AwarenessForm.AddUserToList public method to add the user to the AwarenessForm AwarenessList control. The AddUserForm uses the LookupService to create a Resolver object, which is used to resolve the name the user provides.
Example 11-34 AddUserForm Code
Private MyLookupService As LookupService Private WithEvents MyResolver As Resolver Private MyAwarenessForm As AwarenessForm Public Sub SetAwarenessForm(ByRef AwarenessFrm As AwarenessForm) Set MyAwarenessForm = AwarenessFrm End Sub Private Sub Add_Click() MyResolver.Resolve UserName End Sub Private Sub Form_Load() Set MyLookupService = SametimeSession.GetLookupService Set MyResolver = MyLookupService.CreateResolver(True, True) End Sub Private Sub MyResolver_Resolved(ByVal ev As STComTkLib.IResolveEvent)

Chapter 11. The COM toolkit

335

MyAwarenessForm.AddUserToList ev.GetResolvedUser UserName.SetFocus End Sub Private Sub MyResolver_ResolveFailed(ByVal ev As STComTkLib.IResolveEvent) MsgBox "The name " & ev.FailedName & " was not found try again" UserName.SetFocus End Sub

Private members
The AddUserForm holds three private members: MyLookupService - LookupService member used to create a resolver object. MyResolver - Resolver member used to resolve users. MyAwarenessForm - AwarenessForm member used to call back to the AwarenessForm.AddUserToList method. As seen in Example 11-35, the MyResolver private member is declared using the WithEvents keyword so we can get the Resolved\RsolvedFailed events.
Example 11-35 AddUserForm Private Members
Private MyLookupService As LookupService Private WithEvents MyResolver As Resolver Private MyAwarenessForm As AwarenessForm

SetAwarenessForm public method


This public method is used to tell the AddUserForm to which Form it has to call back when it wants to add a new user using the AwarenessForm.AdduserToList method, It is shown in Example 11-36.
Example 11-36 AddUserForm - SetAwarenessForm Public Method
Public Sub SetAwarenessForm(ByRef AwarenessFrm As AwarenessForm) Set MyAwarenessForm = AwarenessFrm End Sub

Form_Load event
When the user clicks the AddUser button on the AwarenessForm, a new AddUserForm is created. Once the new AddUserForm is created, the Form_Load event is fired.

336

Working with the Sametime Client Toolkits

See Example 11-37. Once the Form_Load event is fired, we set the MyLookupService private member to the one in the SametimeSession and we set MyResolver private member to a new Resolver by using MyLookupService.CreateResolver function. The two parameters we provide the MyLookupService.CreateResolver function are: True to OnlyUnique and True to ExhaustiveLookup.
Example 11-37 AddUserForm - Form_Load
Private Sub Form_Load() Set MyLookupService = SametimeSession.GetLookupService Set MyResolver = MyLookupService.CreateResolver(True, True) End Sub

Add_Click event
Once the user clicks the Add button the Add_Click event is fired. As seen in Example 11-38, once the Add_Click event is fired we call MyResolver.Resolve function to resolve the name the user provided in the UserName text field.
Example 11-38 AddUserForm - Add_Click event
Private Sub Add_Click() MyResolver.Resolve UserName End Sub

MyResolver_Resolved event
The Resolved event is fired when the name the user provided has been successfully resolved. As seen in Example 11-39, once the MyResolver_Resolved event is fired we call the AwarenessForm.AddUserToList public methods by using the MyAwarenessForm private members. When we call the MyAwarenessForm.AddUserToList method, we pass this method the resolved user we get from the ResolveEvent. This is done by calling ResolveEvent.GetResolvedUser function.
Example 11-39 AddUserForm - MyResolver_Resolved event
Private Sub MyResolver_Resolved(ByVal ev As STComTkLib.IResolveEvent) MyAwarenessForm.AddUserToList ev.GetResolvedUser UserName.SetFocus End Sub

Chapter 11. The COM toolkit

337

MyResolver_ResolveFailed event
The ResolveFailed event is fired if the server fails to resolve the name the user has provided. See Example 11-40. If the MyResolver_ResolveFailed event is fired, we create a message box showing the name that failed to be resolved. This name is a property of the ResolveEvent.
Example 11-40 AddUserForm - MyResolver_ResolveFailed event
Private Sub MyResolver_ResolveFailed(ByVal ev As STComTkLib.IResolveEvent) MsgBox "The name " & ev.FailedName & " was not found try again" UserName.SetFocus End Sub

11.5.5 Changing my own status - the ChangeStatusForm


The ChangeStatusForm is used for changing our online status. You can see the form in Figure 11-10.

Figure 11-10 ChangeStatusForm

This form has one ImageCombo control (StatusImageCombo), which represents the current and the new statuses, a status description field so we can add some more text to describe the new status, and a Change button to change the status. When the form is loaded, StatusImageCombo is used for showing the current status of the user. The ChangeStatusForm also has an ImageList control (StatusImageList), which provides the StatusImageCombo with its icons. You can see the initialization code for the form in Example 11-41 on page 338.
Example 11-41 ChangeStatusForm Code
Private WithEvents MyCommunityService As CommunityService Private WithEvents MyLogin As Login Private Sub Form_Load()

338

Working with the Sametime Client Toolkits

Set MyCommunityService = SametimeSession.GetCommunityService If Not IsNull(MyCommunityService) Then Set MyLogin = MyCommunityService.Login End If StatusImageCombo.ComboItems.Add 1, "ActiveStatus", "Active", 1 StatusImageCombo.ComboItems.Add 2, "AwayStatus", "Away", 2 StatusImageCombo.ComboItems.Add 3, "DNDStatus", "Do Not Disturb", 3 Select Case MyLogin.GetMyStatus.StatusType Case IST_USER_STATUS_ACTIVE StatusImageCombo.ComboItems.Item(1).Selected = True Case IST_USER_STATUS_AWAY StatusImageCombo.ComboItems.Item(2).Selected = True Case IST_USER_STATUS_DND StatusImageCombo.ComboItems.Item(3).Selected = True End Select End Sub Private Sub ChangeStatus_Click() If StatusDescription = "" Then MsgBox "Please enter ststus description" StatusDescription.SetFocus Else Dim UserStatus As New STUserStatus Select Case StatusImageCombo.SelectedItem.Key Case "ActiveStatus" UserStatus.StatusType = IST_USER_STATUS_ACTIVE Case "AwayStatus" UserStatus.StatusType = IST_USER_STATUS_AWAY Case "DNDStatus" UserStatus.StatusType = IST_USER_STATUS_DND End Select UserStatus.StatusDescription = StatusDescription MyLogin.ChangeMyStatus UserStatus End If End Sub Private Sub MyLogin_MyStatusChanged(ByVal ev As STComTkLib.IMyStatusEvent) Unload Me End Sub

Private members
The ChangeStatusForm holds two private members: MyCommunityService and MyLogin. It holds the MyCommunityService parameter so it can get the Login object, and a Login parameter so we can change our own status. As seen in Example 11-42, the MyLogin private member is declared with the WithEvents keyword so we can get the MyStatusChanged event.

Chapter 11. The COM toolkit

339

Example 11-42 ChangeStatusForm Private Members


Private WithEvents MyCommunityService As CommunityService Private WithEvents MyLogin As Login

Form_Load event
When the user clicks the ChangeStatus button on the AwarenessForm, a new ChangeStatusForm is created. Once a new ChangeStatusForm is created, the Form_Load event is fired. See Example 11-43. When the Form_Load event is fired, the following steps are taken: 1. The MyCommunityService object is referenced to the one in the SametimeSession. 2. The MyLogin object is referenced to the Login parameter of MyCommunityService object. 3. All items are added to the StatusImageCombo control. 4. The selected item in the StatusImageCombo control is set by getting my status from the MyLogin object.
Example 11-43 ChangeStatusForm - Form_Load event
Private Sub Form_Load() Set MyCommunityService = SametimeSession.GetCommunityService If Not IsNull(MyCommunityService) Then Set MyLogin = MyCommunityService.Login End If StatusImageCombo.ComboItems.Add 1, "ActiveStatus", "Active", 1 StatusImageCombo.ComboItems.Add 2, "AwayStatus", "Away", 2 StatusImageCombo.ComboItems.Add 3, "DNDStatus", "Do Not Disturb", 3 Select Case MyLogin.GetMyStatus.StatusType Case IST_USER_STATUS_ACTIVE StatusImageCombo.ComboItems.Item(1).Selected = True Case IST_USER_STATUS_AWAY StatusImageCombo.ComboItems.Item(2).Selected = True Case IST_USER_STATUS_DND StatusImageCombo.ComboItems.Item(3).Selected = True End Select End Sub

340

Working with the Sametime Client Toolkits

Important: The Login property of the CommunityService is valid only when the user is currently logged into the server.

ChangeStatus_Click event
The ChangeStatus_Click event is fired when the user clicks the ChangeStatus button. As seen in Example 11-44, once the ChangeStatus_Click event is fired, we check to see whether the user has entered a status description. If he has not, we create a message box telling him to put one in; if he has, we create a new STUserStatus object by using the New keyword. We fill the UserStatus object with the new status according to the StatusImageCombo selected item and the new description the user entered. Finally, we change our status by calling the Mylogin.ChangeMyStatus function and passing it the UserStatus object.
Example 11-44 ChangeStatusForm - ChangeStatus_Click event
Private Sub ChangeStatus_Click() If StatusDescription = "" Then MsgBox "Please enter ststus description" StatusDescription.SetFocus Else Dim UserStatus As New STUserStatus Select Case StatusImageCombo.SelectedItem.Key Case "ActiveStatus" UserStatus.StatusType = IST_USER_STATUS_ACTIVE Case "AwayStatus" UserStatus.StatusType = IST_USER_STATUS_AWAY Case "DNDStatus" UserStatus.StatusType = IST_USER_STATUS_DND End Select UserStatus.StatusDescription = StatusDescription MyLogin.ChangeMyStatus UserStatus End If End Sub

MyLogin_MyStatusChanged event
The MyStatusChanged event is fired when the user successfully changed his own status.

Chapter 11. The COM toolkit

341

Attention: When two Sametime clients are running under the same user on the same machine and one of the clients changes his own status, MyStatusChanged will be fired in both clients

As seen in Example 11-45, once the MyLogin_MyStatusChanged event is fired, the only thing we do is to close the form.
Note: If the user added himself to the AwarenessList, the UserStatusChanged event will also be fired. That way, the AwarenessList will be updated with the new status.
Example 11-45 ChangeStatusForm - Mylogin_MyStatusChanged event
Private Sub MyLogin_MyStatusChanged(ByVal ev As STComTkLib.IMyStatusEvent) Unload Me End Sub

This completes the description of the Awareness sample.

11.6 The BuddyList sample


We now describe our third and final step, the BuddyList sample that uses most of the COM Toolkit capabilities. The BuddyList sample extends the Awareness sample by using the Instant Messaging Service to add Chat capability. All the code from the Awareness Sample is valid for this sample, except where noted. This is a full sample using Awareness, Lookup, Community, and Instant Messaging Services that enable us to login/logout, be aware of other users, and chat with them.

342

Working with the Sametime Client Toolkits

Figure 11-11 BuddyList Sample

11.6.1 Initialize Sametime service - the SametimeSession module


The SametimeSession Module is expanded by adding the Instant Messaging Service to it. You can see the module code in Example 11-46.
Example 11-46 BuddyList - SametimeSession Module
Private Private Private Private MyCommunityService As CommunityService MyLookupService As LookupService MyAwarenessService As AwarenessService MyImService As InstantMessagingService

Public Sub InitializeSession() Set MyCommunityService = New CommunityService Set MyLookupService = New LookupService Set MyAwarenessService = New AwarenessService Set MyImService = New InstantMessagingService End Sub Public Function GetCommunityService() As CommunityService Set GetCommunityService = MyCommunityService

Chapter 11. The COM toolkit

343

End Function Public Function GetLookupService() As LookupService Set GetLookupService = MyLookupService End Function Public Function GetAwarenessServie() As AwarenessService Set GetAwarenessServie = MyAwarenessService End Function Public Function GetImServie() As InstantMessagingService Set GetImServie = MyImService End Function

Services
The only service which remains to be added in this sample is the Instant Messaging Service. This service is also being held as a private member in the SametimeSession, and provides a get function as seen in Example 11-47.
Example 11-47 SametimeSession - Get the Im Service
Private MyImService As InstantMessagingService . . . Public Function GetImServie() As InstantMessagingService Set GetImServie = MyImService End Function

You may think that there is a spelling error in the GetImServie function, but we keep it as it is to make sure it matches the downloadable code.

Initializing
As we did in the Awareness sample, we initialize the new service in the InitializeSession public method, as seen in Example 11-48.
Example 11-48 SametimeSession - InitializeSession Public Method
Public Sub InitializeSession() Set MyCommunityService = New CommunityService Set MyLookupService = New LookupService Set MyAwarenessService = New AwarenessService Set MyImService = New InstantMessagingService End Sub

344

Working with the Sametime Client Toolkits

11.6.2 Adding Instant Messaging capabilities - the BuddyListForm


The BuddyListForm expands the AwarenessForm from the Awareness sample by adding to it the Chat button and InstantMessaging capabilities. You can see the form in Figure 11-12.

Figure 11-12 BuddyListForm

We are basically using the same code in the BuddyListForm as in the AwarenessForm except for the name of the form. Thus we only show the code added to the form in Example 11-49. You can see the code for the AwarenessForm in Example 11-14 on page 323.
Example 11-49 BuddyListForm Code
.... Private WithEvents MyImService As InstantMessagingService .... Private Sub AwarenessListView_DblClick() Call Chat_Click End Sub ....

Chapter 11. The COM toolkit

345

Private Sub Chat_Click() Dim Item As ListItem Set Item = AwarenessListView.SelectedItem If Not Item.Key = "" Then Dim User As New STUser User.Name = Item.Text User.Id.Id = Item.Key Dim MyIm As Im Set MyIm = MyImService.CreateIm(User, _ IST_ENC_LEVEL_NON, 1) Dim MyChatForm As New ChatForm MyChatForm.Left = Me.Left + Me.Width MyChatForm.Top = Me.Top MyChatForm.Show vbModeless, Me MyChatForm.SetIm MyIm, False End If End Sub .... Private Function MyImService_ImReceived(ByVal ev As STComTkLib.IImEvent) As Long Dim MyChatForm As New ChatForm MyChatForm.Left = Me.Left + Me.Width MyChatForm.Top = Me.Top MyChatForm.SetIm ev.ReceivedIm, True End Function .... End Function

Private members
We have added one more private member, the InstantMessagingService. As seen in Example 11-50, we declare MyImService a private member using the keyword WithEvents so we can get the ImReceived event.
Example 11-50 BuddyList Private Members
Private Private Private Private WithEvents WithEvents WithEvents WithEvents MyCommunityService As CommunityService MyAwarenessService As AwarenessService MyImService As InstantMessagingService MyWatchList As WatchList

346

Working with the Sametime Client Toolkits

Form_Load event
In the Form_Load event we added the initialization of MyImService private member, as seen in Example 11-51.
Example 11-51 BuddyListForm - Form_Load event
Private Sub Form_Load() SametimeSession.InitializeSession Set MyCommunityService = SametimeSession.GetCommunityService Set MyAwarenessService = SametimeSession.GetAwarenessServie Set MyImService = SametimeSession.GetImServie End Sub

Chat_Click event
When the user clicks the Chat button the Chat_Click event is fired. As seen in Example 11-52, once the Chat_Click event is fired, we try to get the selected user from the AwarenessListView and we check its key. If we succeed in getting the key, we create a new STUser object by using the New keyword. After creating a new User, we set its ID and Name to the same ones as the ListItem which was selected. Now we create a new Im object by using the MyImService.CreateIm function, passing it the User object, the encryption level, and the type of the Im.
Note: All Ims in Sametime Clients like Connect and Java Connect are created with type 1. You can create Ims with any type you like, but they wont be accepted by these clients. For example, you can write your own client using type 1002, which will be recognized only by your client.

After we have a valid Im object MyIm, we create a new ChatForm, placing it on the right corner of the BuddylistForm, and finally, setting it the MyIm object by calling MyChatForm.SetIm, and passing it MyIm object and False (to show that this is not a received Im). For more information about ChatForm, refer to Chatting with others - the ChatForm on page 348.
Example 11-52 BuddyListForm - Chat_Click event
Private Sub Chat_Click() Dim Item As ListItem Set Item = AwarenessListView.SelectedItem If Not Item.Key = "" Then Dim User As New STUser User.Name = Item.Text User.Id.Id = Item.Key Dim MyIm As Im Set MyIm = MyImService.CreateIm(User, _ IST_ENC_LEVEL_NON, 1)

Chapter 11. The COM toolkit

347

Dim MyChatForm As New ChatForm MyChatForm.Left = Me.Left + Me.Width MyChatForm.Top = Me.Top MyChatForm.Show vbModeless, Me MyChatForm.SetIm MyIm, False End If End Sub

MyImService_ImReceived event
The ImReceived event is fired when another user sent you a new Im successfully. See Example 11-53. Once the MyImService_ImReceived event is fired, we create a new ChatForm, placing it in the right corner of the BuddyListForm, and finally, pass it the ReceivedIm property of the ImEvent and True (because this Im has been received).
Example 11-53 BuddylistForm - MyImService_ImReceived event
Private Function MyImService_ImReceived(ByVal ev As STComTkLib.IImEvent) As Long Dim MyChatForm As New ChatForm MyChatForm.Left = Me.Left + Me.Width MyChatForm.Top = Me.Top MyChatForm.SetIm ev.ReceivedIm, True End Function

11.6.3 Chatting with others - the ChatForm


You can see our chat form in Figure 11-13.

Figure 11-13 ChatForm

The code for the ChatForm is shown in Example 11-54.


348

Working with the Sametime Client Toolkits

Example 11-54 ChatForm Code


Private WithEvents MyIm As Im Private ImWasReceived As Boolean Private MyName As String Public Sub SetIm(ByRef NewIm As Im, ByVal WasReceived As Boolean) Set MyIm = NewIm ImWasReceived = WasReceived If Not ImWasReceived Then MyIm.Open End If End Sub Private Sub Close_Click() Unload Me End Sub Private Sub Form_Load() MyName = SametimeSession.GetCommunityService.Login.GetMyUserName End Sub Private Sub Form_Unload(Cancel As Integer) If Not IsNull(MyIm) Then MyIm.Close IST_OK End If End Sub Private Sub MyIm_ImClosed(ByVal ev As STComTkLib.IImEvent) TrnscriptText.Enabled = False MessageText.Enabled = False Send.Enabled = False End Sub Private Sub MyIm_ImOpened(ByVal ev As STComTkLib.IImEvent) TrnscriptText.Enabled = True MessageText.Enabled = True Send.Enabled = True Me.Show End Sub Private Sub MyIm_OpenImFailed(ByVal ev As STComTkLib.IImEvent) MsgBox "Im open fail." & vbNewLine & _ "Reason : " & ev.Reason End Sub Private Sub MyIm_TextReceived(ByVal ev As STComTkLib.IImEvent) If ImWasReceived And Me.Visible = False And MyIm.IsOpen Then Me.Show vbModeless

Chapter 11. The COM toolkit

349

End If TrnscriptText.Text = TrnscriptText.Text & _ MyIm.GetPartner.Name & _ " : " & ev.Text & vbNewLine End Sub Private Sub Send_Click() TrnscriptText.Text = TrnscriptText.Text & _ MyName & " : " & _ MessageText.Text & vbNewLine MyIm.SendText 0, MessageText.Text MessageText.Text = "" End Sub

Private members
The ChatForm has three private members : MyIm - an Im private member, the Im which is used to send/receive text. ImWasReceived - a Boolean private member, this indicates when the Im was created by another user and received by us. MyName - this String private member holds my user name. As seen in Example 11-55, the MyIm private member is declared with the WithEvents keyword so we can get the ImOpened, ImClosed, TextReceived, and some other events related to the Im Interface.
Example 11-55 ChatForm Private Members
Private WithEvents MyIm As Im Private ImWasReceived As Boolean Private MyName As String

SetIm public method


The SetIm public method is used for setting the Im object and the ImWasReceived private members. When we want to create a new ChatForm for a new Im that was created by us or an Im that was received, we first create a new ChatForm and then pass it the Im object and True if the Im was received or False otherwise. Example 11-56 shows how we set these parameters.
Example 11-56 ChatForm SetIm Public Method
Public Sub SetIm(ByRef NewIm As Im, ByVal WasReceived As Boolean) Set MyIm = NewIm ImWasReceived = WasReceived If Not ImWasReceived Then MyIm.Open End If

350

Working with the Sametime Client Toolkits

End Sub

Form_Load event
Once the user clicks on the Chat button or a new Im is received, we create a new ChatForm. If the ChatForm was created because the user pressed the Chat button, we call the Me.Show function in the ChatForm once the ImOpened event is fired, then the Form_Load event is fired. Another case is when an Im is Received. In this case we create a new ChatForm and wait for a text to be received. Once a text is received, we call the Me.Show function inside the ChatForm. Once this is done, the Form_Load event is fired. Refer to Example 11-62 on page 353 to see what we do when the TextReceived event is fired. As seen in Example 11-57, once the Form_Load event is fired, the only thing we do is to set the MyName parameter to the user name we get from the Login object.
Example 11-57 ChatForm - Form_Load event
Private Sub Form_Load() MyName = SametimeSession.GetCommunityService.Login.GetMyUserName End Sub

MyIm_ImOpened event
The ImOpened event is fired once the Im.Open function succeeds in opening the Im.
Note: Youll receive an ImOpened event only if you created a new Im object using the InstantMessagingService.CreateIm function and called Im.Open. You wont get this event when you receive an Im from another user.

See Example 11-58. When MyIm_ImOpened is fired, we first enable all the controls of the form, like TranscriptText and Send button, and then we call Me.Show function to show the window.
Example 11-58 ChatForm - MyIm_ImOpened event
Private Sub MyIm_ImOpened(ByVal ev As STComTkLib.IImEvent) TrnscriptText.Enabled = True MessageText.Enabled = True Send.Enabled = True Me.Show End Sub

Chapter 11. The COM toolkit

351

MyIm_OpenImFailed event
The OpenImFailed event is fired if the Im.Open function failed to open the Im. As seen in , if the MyIm_ImOpenedFailed event is fired, the only thing we do is create a message box containing the reason for the failure.
Example 11-59 ChatForm - MyIm_OpenImFailed event
Private Sub MyIm_OpenImFailed(ByVal ev As STComTkLib.IImEvent) MsgBox "Im open fail." & vbNewLine & _ "Reason : " & ev.Reason End Sub

MyIm_ImClosed event
The ImClosed event is fired when the Im object is closed. Im is closed once one of the users who are chatting calls the Im.Close function and passes it the reason for the close. Another example of a reason for a closed Im is a network problem. This can be verified by the reason we get from ImEvent.Reason property. As seen in Example 11-60, once MyIm_ImClosed is fired, we disable all the ChatForm controls.
Example 11-60 ChatForm - MyIm_ImClosed event
Private Sub MyIm_ImClosed(ByVal ev As STComTkLib.IImEvent) TrnscriptText.Enabled = False MessageText.Enabled = False Send.Enabled = False End Sub

Send_Click event
The Send_Click event is fired when the user clicks the Send button to send the text to another chat user. See Example 11-61. When the Send_Click event is fired, we add the text to the transcript window and send it to the other user using the MyIm.Send function and passing it the text we want to send. Finally, we clear the MessageText field.
Example 11-61 ChatForm - Send_Click
Private Sub Send_Click() TrnscriptText.Text = TrnscriptText.Text & _ MyName & " : " & _ MessageText.Text & vbNewLine MyIm.SendText 0, MessageText.Text MessageText.Text = "" End Sub

352

Working with the Sametime Client Toolkits

MyIm_TextReceived event
The TextReceived event is fired when the other chat user sends us new text. As seen in Example 11-62, once MyIm_TextReceived event is fired, we check whether the Im object we have was received; if it is, we check to see if the form is visible. Once both conditions are True, we call Me.Show function to load the form. Details about loading the ChatForm were presented previously. Next we take the text and user name from the ImEvent and put them in the transcript window so the user can see the message that was sent.
Example 11-62 ChatForm - MyIm_TextReceived event
Private Sub MyIm_TextReceived(ByVal ev As STComTkLib.IImEvent) If ImWasReceived And Me.Visible = False And MyIm.IsOpen Then Me.Show vbModeless End If TrnscriptText.Text = TrnscriptText.Text & _ MyIm.GetPartner.Name & _ " : " & ev.Text & vbNewLine End Sub

Close_Click event
The Close_Click event is fired when the user clicks the Close button. You can see in Example 11-63 how we handle the Close_Click event. We close the form by calling the Unload function.
Example 11-63 ChatForm - Close_Click event
Private Sub Close_Click() Unload Me End Sub

Form_Unload event
When we call the Unload function the Form_Unload event is fired. As seen in Example 11-64, after we check whether the MyIm object is valid, we close the Im by calling the MyIm.Close function, passing it IST_OK as a reason for the closing. This will close the Im object in both sides (both users will get the notification for the closing).
Example 11-64 ChatForm - Form_Unload event
Private Sub Form_Unload(Cancel As Integer) If Not IsNull(MyIm) Then MyIm.Close IST_OK End If End Sub

Chapter 11. The COM toolkit

353

This completes our description of the third and final step in our sample. In these three steps we have shown you how to use the Sametime services provided by the Sametime COM toolkit. With this knowledge you can now add awareness and chat capabilities to any applications that supports Visual Basic/VBA or LotusScript.

11.7 Summary
In this chapter we introduced the Sametime COM toolkit. We told you how to get the toolkit and how to use it with Visual Basic. The major part of the chapter covered a sample that shows how to use all the Sametime services offered by the COM toolkit. First, we showed you how to use the community service to log in and out from Sametime. The we added the LookupService to help us find other Sametime users and the AwarenessService to see the status of those other users. Finally, we added the Instant messaging service that allows us to chat with another Sametime user. We have shown how the Sametime COM toolkit makes it easy for you to enable your Visual Basic/VBA/LotusScript applications for real time awareness and communication with a limited effort.

354

Working with the Sametime Client Toolkits

12

Chapter 12.

The Sametime Links toolkit


We have now come to the last Sametime toolkit that we will discuss in this book. It does not come last because it is the most complex; on the contrary, it is probably the simplest to use of the toolkits. Sametime Links is a light toolkit that allows Web developers to Sametime-enable their Web pages and applications with live names. A simple HTML/JavaScript API allows Web developers to turn existing names into Sametime links by simply adding a few lines of HTML, without affecting the layout of the page. While rich in functionality, it is light in size, using an embedded applet of only 20K. Figure 12-1 on page 356 shows an example of a Web application enabled with Sametime.

Copyright IBM Corp. 2002. All rights reserved.

355

Figure 12-1 An example of a Web application enabled with Sametime

12.1 Toolkit features


Table 12-1 provides an overview of the features provided by the Sametime Links Toolkit.
Table 12-1 Features of the Sametime LInks toolkit
Feature Simple API Description Using any Web design tool, existing names in a Web page are turned into Sametime links simply by adding a few lines of HTML. No programming or layout changes are required to enable a Web page. The total size of the applet embedded in the Web page/application is approximately 20K. Awareness with status icons, instant messages and n-way chat, launch instant meetings, set status. (Details follow.)

Light weight Rich feature set

356

Working with the Sametime Client Toolkits

Feature Advanced JavaScript API

Description Provides access to additional Sametime functionality and allows you to customize the behavior and look and feel of the live name. (Details follow.) The integration with the site/application should be transparent to the end-user. No installation or code that requires execution privileges (signed applet). The HTML files of the Sametime Links dialogs can be copied to any Web application server. Uses HTTP to communicate with the Sametime server for connectivity (works through firewalls). Supports password, anonymous, and transparent authentication by access token. No need to challenge users that have already logged onto the Web application. The same level of chat encryption provided by other Sametime clients. Windows 95/98/NT/2000, with MSIE 5 and above, and Netscape 4.7x and above. Sametime Links works out-of-the-box on Sametime server version 2.6 and above. A standalone add-on installation will be provided for Sametime 2.5 as well. The UI is HTML, and is fully customizable. It is also ADA-compliant, to the extent that HTML is. Localized for the full set of languages offered by Lotus Sametime. The Sametime server supports very large numbers of Sametime Links users.

No Installation

Extranet support Authentication

Encryption Supported platforms Sametime server compatibility Customizable Localized UI Scalable

Chapter 12. The Sametime Links toolkit

357

12.1.1 Awareness
Names become live, indicating the online status of the user and allowing real-time communication. The status can be displayed with an optional status indicator next to the name. The default status icons provided can be modified or replaced by the Web author. The status message set by the user is displayed in a floating tool tip over the user name as you can see in Figure 12-2.

Figure 12-2 User message displayed as tool tip

12.1.2 Instant messages


A single click on the name of an online user starts an instant message with that user in a new window. This HTML window provides much of the same functionality as the Sametime Connect instant message window, including a color-coded transcript, URLs that are HTML links, and a responding indication. You can see an example of the HTML chat window in Figure 12-3.

Figure 12-3 HTML chat window

358

Working with the Sametime Client Toolkits

N-Way chat/Chat meetings


An instant message session can be extended to a chat meeting (also called n-way chat) by inviting additional people. You can see an example of this in Figure 12-4.

Figure 12-4 Chat meeting

In addition, the API supports starting an n-way chat by selecting multiple users from the Web page.

12.1.3 Meetings
Additional meeting tools can be added to both the Instant Message and N-Way Chat windows to launch the standard Sametime Meeting Room client.

12.1.4 Set status


The API provides a method for the Web developer to add a link allowing the user to change his online status and message. You can see the change status window in Figure 12-5 on page 360.

Chapter 12. The Sametime Links toolkit

359

Figure 12-5 Change My Online Status window

12.1.5 Place-based awareness


The API allows the Web developer to add a place-based awareness link and a people counter to a Web page or application. The people counter is updated in real-time as visitors enter and leave the place. Clicking on the place-based awareness link opens a window with a list of people in the place. You can see an example of this in Figure 12-6 on page 361.

360

Working with the Sametime Client Toolkits

Figure 12-6 Place-based awareness

12.1.6 Chat rooms


The API allows the Web developer to embed a link to launch a place-based chat room. You can see an example of this in Figure 12-7 on page 362.

Chapter 12. The Sametime Links toolkit

361

Figure 12-7 Place-based chat

12.1.7 Advanced JavaScript API


The advanced Sametime JavaScript API allows you to: Access additional Sametime functionality Customize the behavior of Sametime Links Customize the look and feel of the Sametime links The JavaScript API allows you to access additional Sametime functionality, for example: log on, log out, add names and groups to the watch list, create instant messages and meetings, add a name to the contact list, enter and leave a place, and check availability of multimedia services. You can customize the behavior of Sametime Links by catching the generated events and handling them in the manner of your choosing.

362

Working with the Sametime Client Toolkits

For example, when a Sametime link is clicked, you could display a popup menu providing options for creating an instant message or a meeting, as well as other options like sending mail. Another example is generating an alert each time someone enters a place. Finally, you can customize the look and feel of Sametime links by catching the status changed events and displaying the status differently. An example of this is displaying only people that are currently online in a list.

12.2 Getting started


Sametime Links comprises runtime and toolkit components. The runtime components are installed on the Sametime server during the server installation. The runtime components include: Sametime Links server application, which is installed with the other server applications JavaScript and HTML files (installed in the html/sametime/stlinks folder under the Sametime server installation): stlinks.js Sametime Links JavaScript HTML and Gif files provide the UI for Sametime Links Since the API is in HTML/JavaScript, you do not need to download anything to utilize the toolkit in your browser applications. To access the pages that include the documentation and samples, follow these steps: 1. Navigate to the home page of your Sametime 3.x server:
http://<your_sametime_server_name>

2. Click the Toolkit link at the bottom of the page. You might need to scroll down the page to see the link. 3. Click Sametime Links Toolkit on the Toolkits page.

12.2.1 Enabling a Web application


This section provides a sample to illustrate the simplicity of enabling your Web applications with Sametime Links.

Chapter 12. The Sametime Links toolkit

363

Preparing the Web page for adding Sametime Links


This sample shows you how to include the necessary files, embed the hidden applet, and add Sametime Links to the HTML text. 1. Include the necessary files by adding the following HTML code to the Head HTML section:
<LINK REL=STYLESHEET HREF="codeBase/stlinks.css" TYPE="text/css"> <SCRIPT src="codebase/stlinks.js"></SCRIPT> <script> setSTLinksURL("codebase"); </script>

where codeBase is the URL of the directory where the Sametime Links runtime package is installed. (http://<sametimeserver>/sametime/stlinks, where <sametimeserver> is your Sametime server host name. 2. Add the code that puts the hidden Sametime Links Java applet on the page. This code can be put anywhere within the HTML code of your page, because the applet itself is placed on a hidden zero-size HTML layer.
<script> writeSTLinksApplet (loginName, </script> key, isByToken, port);

where: loginName is the login name of the user. key is the password or token. isByToken is true if you use a token to authenticate, false for password; default is false. port is the port that will be used for communication with the server. The default is port 80.

12.2.2 Authentication considerations


You can authenticate users of Sametime Links to Sametime in one of three ways: Single Signon Use Light Third-Party Authentication (LTPA) if you are adding Sametime Links to a Lotus Notes form or a Web application that already required a login. A sample Domino Web application and additional information will be available when the Toolkit is released. Anonymous To log in as anonymous, pass an empty string as the password. This is useful for providing real-time help in an e-commerce environment. Password authentication Use password authentication when you test your implementation.

364

Working with the Sametime Client Toolkits

12.2.3 Adding a Sametime link


Once you have prepared the page for adding Sametime Links, you add a Sametime link anywhere within the HTML text by typing the following:
<script>writeSametimeLink(userName, displayName, bResolve, options)</script>

where:
userName is the unique user name. To ensure uniqueness, use the canonical name, or the distinguished name if you are using an LDAP directory. However, note that Sametime server 2.5 cannot resolve distinguished names. Therefore, if you are using Sametime server 2.5 with LDAP, use the users common name. displayName is the display name of the user. bResolve is true if the Sametime server has to resolve the user name. False indicates that the user name is already resolved. options is a string of semicolon-delimited display options. Each element in the list has the format "option:value". The options allow changing the rendering and the behavior of the Sametime link. For example, by specifying "text:yes; icon:no" you create a Sametime link without a status icon.

Chapter 12. The Sametime Links toolkit

365

12.2.4 A simple online assistance sample


Using the instructions in the preceding section, we enabled a Web page about a cross country trip so anybody visiting the page can chat with one of the trip participants if they also happen to be online. Figure 12-8 shows a chat initiated via the enabled Web page that has been turned into a chat meeting.

Figure 12-8 Web page enabled for awareness and chat by the Sametime Links toolkit

We enabled the page as described earlier in this section and added the four links you can see on the page (Sren P, Dick, Harriett and Crocodile Frank). In Example 12-1 on page 367 you can see the code we added to the Web page in order to enable it for awareness and chat.

366

Working with the Sametime Client Toolkits

Example 12-1 Code required to Sametime enable page shown in Figure 12-8
<html> <head> ... ... <LINK REL=STYLESHEET HREF="http://bigdaddy.lotus.com/sametime/stlinks/runtime/stlinks.css" TYPE="text/css"> <SCRIPT src="http://bigdaddy.lotus.com/sametime/stlinks/runtime/stlinks.js"></SCRIPT> <script> setSTLinksURL("http://bigdaddy.lotus.com/sametime/stlinks/runtime"); </script> </head> <body> <table> ... ... <tr>The members from the trip listed below are regularly online. When their name is green you can click on it to chat with them. </tr> <tr> <script>writeSametimeLink("Soren P", "Sren P", true)</script> <script>writeSametimeLink("Dick", "Dick", true)</script> <script>writeSametimeLink("Harriett", "Harriett", true)</script> <script>writeSametimeLink("Frank Furrer", "Crocodile Frank", true)</script> </tr> ... </table> ... ... <script> writeSTLinksApplet("WebVisitor", "", false); </script> </body> </html>

Note that the password argument for the writeSTLinksApplet statement is an empty string. This means everybody who loads this page gets anonymously logged into the Sametime server. Even though each user will have WebVisitor as their display name, they will get separate sessions. If we already had the users name in a cookie or by other means, we could of course pass that name

Chapter 12. The Sametime Links toolkit

367

along when logging in anonymously instead of the generic name WebVisitor. In order to use anonymous users in the context we see here, the Sametime server must be configured to allow anonymous users to resolve users and groups. In Sametime 2.5 this is not allowed by default. Also notice the statements that specify the codebase for the Sametime Links runtime components. You will see that we specify a fully qualified server name. This allows us to host our Web page on the Web server, where it always has been located, and simply uses the Sametime server for Sametime Links functionality. As you saw in this simple sample, the Sametime Links toolkit enables you to add awareness, chat, and chat meeting capability with just a few Web page modifications, and no changes required for your existing infrastructure. This concludes our overview of the Sametime Links toolkit. Check the Sametime Toolkit Developers Guide, installed on your server with the toolkit, for more details on utilizing this capability on your Web applications.

12.3 Summary
In this chapter we covered the capabilities of the Sametime Links toolkit. This toolkit is perfect for Web developers. It allows the addition of awareness and real-time communication capabilities to a Web page without requiring any knowledge about Sametime programming. In addition, the toolkit is lightweight. It only requires download of a small (approximately 20K) applet and some JavaScript and HTML code.

368

Working with the Sametime Client Toolkits

Part 5

Part

Appendixes

Copyright IBM Corp. 2002. All rights reserved.

369

370

Working with the Sametime Client Toolkits

Appendix A.

Some deployment considerations


In this redbook our scope is application development. However, application deployment is just as important. In this appendix we list a few considerations we discussed during the work on this book.
Note: This is absolutely not an exhaustive list of application deployment considerations, but just a few topics that we came upon during our work that we want to share with you.

Infrastructure for anonymous users


While the Sametime server offers some settings to limit the actions anonymous users can perform, you may want to consider having two infrastructures for Sametimeone with anonymous access allowed, one withoutif you want to ensure that confidential data is never visible to anonymous users. This may be needed because you cannot ensure that all your applications are anonymous-aware, meaning that they test anonymous users and behave differently. Anonymous users can use the community services to change a part of the user name.

Copyright IBM Corp. 2002. All rights reserved.

371

Applet connections over the Internet


If you want to run your application on the internet, you will need to understand and manipulate the connection settings. As you can see on Figure 2-2 on page 20, Sametime establishes a TCP/IP network connection between the client application and the Sametime server. In todays world the internet interconnects the networks of millions of companies and organizations. These normally protect their local networks using firewalls and allowing users only to connect to the internet using special HTTP or SOCKS proxy servers. The Sametime toolkit is designed to automatically try all its connection options when the application connects to the server, but it may fail to do so. This section discusses what you can do to succeed. Sametime supports 2 basic types of connections: direct socket connections and HTTP connections. Direct connections are usually only possible if the user has no firewall in place, or if the firewall allows outgoing connections. HTTP connections try to establish a connection using the HTTP protocol; this is often referred to as HTTP tunneling. The default behavior of the Sametime toolkit is to try a direct socket connection to the server, and, if it fails, to try two different types of HTTP tunneling connections afterwards. If all fails, you will receive a loggedOut() event with a reason describing the problem. Now you need to help the toolkit to connect successfully. There are two options you may support: First, try to equip your applet with all connection options that you, as the application owner, know aboutespecially your server configuration. If you, for example, change the default tunneling ports, the tunneling will not be successful since the toolkit does not know about this. So you can create a series of Connection objects and offer them to the Community service using setConnectivity() describing your knowledge about the server side. Additionally, you may want to allow the user of your application to configure him own internet connectivity options, like a SOCKS proxy or similar. An application that works this way is the Sametime Connect client; you can see the configuration options in Figure A-1 on page 374. If your application is supposed to work in firewalled and/or proxy environments, ensure that you do the following: 1. Subclass your applet from STApplet, not from Applet, to inherit proxy PAC file support. 2. Test the application in an environment without firewalls and proxies first.

372

Working with the Sametime Client Toolkits

3. Create a connection table, including a direct connection in the beginning of the list, and test again in this environment. 4. Set up the firewalled and/or proxy-environment like this: a. Read the Sametime Installation Guide (stinstall.pdf) and the Sametime Administrators Guide (sthelpad.pdf) supplied in the directory Docs on the Sametime CD. b. Read the redbook Lotus Sametime 2.0 Deployment Guide, SG24-6206 for an overview of typical scenarios. c. Use a port filtering router between the client and the server, and filter the ports you do not want to use, for instance, the direct connection ports. d. Change the server configuration to listen on another port for direct connections, so that HTTP tunneling is enforced. e. Really use a proxy server and try some typical LAN configurations and proxy setups. 5. Verify a correct server setup with scheduled and instant meetings, as well as the Sametime 3.0 connect clients. 6. Test the application again using the new setup.
Notes:

Direct connections are usually more effective than tunneling connections. The tunneling option is always the last chance to connect, but you may want to discuss connection options with your customers, for instance in a B2B environment. What kind of proxy servers are involved? There are several types of servers called Proxy Servers: HTTP or SOCKS Proxy Servers, which you configure in your browser. Protocol proxy servers/routers, which protect a server from direct access and verify that the requests are protocol consistent.

Appendix A. Some deployment considerations

373

Figure A-1 Sametime Connect for Browsers - Connectivity settings

Instant messaging and data transfer


You may want to transfer larger amount of data using the IM service. Be aware that the service is not designed to do this. Sametime itself transfers larger amounts of data with separate services, such as what is done in the meeting services. Consider the following items when planning your application: Split the data in small segments. If you try to send a large chunk, no other events can arrive while the data is being transferred. Verify that all segments are received. Think about a direct peer-to-peer connection instead of using the server. Think about sending e-mail instead.

374

Working with the Sametime Client Toolkits

Appendix B.

Working with the auction house sample material


In this appendix we give you a few hints to get more out of the additional Web material for the auction house sample we described in Chapter 6, A place-based auction example on page 101. We describe how you can install the sample as a runtime version to try out the implemented functionality, and after that we show you how you can see the JavaDoc for the application, as well as the full source code, simply by using a Web browser. See Appendix E, Additional Web material on page 407 for instruction on how to get the Web material.

Copyright IBM Corp. 2002. All rights reserved.

375

Installing the auction house sample


The installation of the auction house sample is very simple, but it requires that you already have a Sametime 2.5 or higher server installed and running. Download the zipped sample application in the file 6666auctionapp.zip from the IBM Redbooks Web site as described in Appendix E, Additional Web material on page 407. Unzip it into the HTML directory. This directory is usually
C:\Sametime\Data\Domino\html or C:\Lotus\Domino\Data\Domino\html

A directory called auction will be created, containing: 6666auction.jar HTML files: Auctioneer.html AuctionCustomer.html Image files for the auction items If you stick to this directory structure the HTML files will refer with correct path to the Sametime 3.0 Toolkit jar/cab-files. Otherwise, find the Sametime Java Toolkit files CommRes.jar/cab and STComm.jar/Cab; copy them into this directory and modify the HTML files to point to the files in the same directory. Now you can launch the auctioneer using:
http://<server>/auction/auctioneer.html Important: You must launch the Auctioneer before you start any AuctionCustomer (bidder) clients. This is because the Auctioneer first must create the place to enter. You will receive an error if an AuctionCustomer tries to enter a non-existent place.

The bidders use:


http://<server>/auction/auctioncustomer.html

You can launch all clients on the same computer.

Looking at the code


If you want to browse through the auction house classes, you can use the JavaDoc supplied. The JavaDoc files contain the important comments, and they linking together the classes, interfaces, and methods. Figure 12-9 on page 377 shows the initial JavaDoc page, listing all classes in the auction house sample.

376

Working with the Sametime Client Toolkits

Figure 12-9 Auction house sample JavaDoc

Similar to JavaDoc, we provide also the complete source in HTML format, generated using a tool named Java2HTML. The usage is similar to JavaDoc, but youll have the Java source with Syntax highlighting. See Figure 12-10 on page 378 for an example of this.

Appendix B. Working with the auction house sample material

377

Figure 12-10 HTML version of the Auction House Java source

In addition, an integrated development environment like VisualAge for Java helps to browse through classes and methods, and easily to make modifications to our samples so that you can quickly start experimenting. Figure 12-11 shows an example of VisualAge for Java 4.0 with our sample classes loaded.

378

Working with the Sametime Client Toolkits

Figure 12-11 Class browsing with VisualAge for Java

The classes to start with are the two applets Auctioneer and AuctionCustomer, inheriting from AuctionUser. In AuctionUser youll find the common behavior of the two subclasses.

Scenario
If you want to get an idea of an auction scenario, see Appendix C, Sample auction scenario on page 381, where we walk you through an auction scenario and show screen captures of what is going on in the user interface for each step.

Appendix B. Working with the auction house sample material

379

380

Working with the Sametime Client Toolkits

Appendix C.

Sample auction scenario


In this appendix we take you through an online bidding scenario performed with the sample application we described in Chapter 6, A place-based auction example on page 101.

Copyright IBM Corp. 2002. All rights reserved.

381

The scenario
We have defined some users and their roles as we step through the auction; see Table 12-2 for details. The auction is used to sell picture artwork to interested customers all over the world.
Table 12-2 User roles
User Volker Juergensen Tom Talbert Jim Jackson Frank Furrer Role and remarks Auctioneer Tom is really interested in the Arizona Sun picture. He logs into the auction directly with his userid and password. Jim is also an art fan, and interested in almost any expensive item. So he logs into the auction. Frank is hitting the Web site announcing the auction by accident, and enters anonymously first. Once in the auction, he becomes interested, logs in, and starts bidding. Sam is interested in all kinds of art, but has no money to buy. He is happy that he can attend the auction as an anonymous user.

Sam Smith

Preparation
The auction items are one classic picture, Arizona Sun by Laura Nielsen, and a prototype of a wearable PC. Some pictures have been prepared and the auctioneers application parameters were set up as shown in Example C-1.
Example C-1 Auctioneers applet parameters
... <APPLET ... > <param name=archive ...> <param name=DefaultImageURL value="default.jpg"> <param name=numItems value=2> <param name=Item1Title value="Arizona Sun"> <param name=Item1URL value="AZSunc.jpg"> <param name=Item1Price value=1000> <param name=Item2Title value="Wearable PC"> <param name=Item2URL value="wearpclg.gif"> <param name=Item2Price value=500> </APPLET> ...

382

Working with the Sametime Client Toolkits

Remember, it is just to keep thing simple that we pass the auction item information as applet parameters. In the real world this information will be fetched as XML data from some kind of content management system, relational database, or similar. Also, the auction has been announced on a Web site and some invitations to good customers have been sent.

Entrance
Since we use simple static HTML pages, the auction participants use a URL like this to enter the auction:
http://<server>/<directory>/<filename>.html

In our scenario the URLs are as follows: Auctioneer:


http://medion.lotus.com/auction/auctioneer.html

Auction customers:
http://medion.lotus.com/auction/auctioncustomer.html

Tom and Jim use their user name and password for authentication, while Frank and Sam only type in their first name and click the Anonymous button of the login dialog, shown in Figure C-1.

Figure C-1 Login dialog

After all users have entered, every user has a personalized view of the auction. The auctioneer has the most information available since he is monitoring the anonymous user list as well as the auditorium users (who are already logged in with their passwords). As you can see in Figure C-2 on page 384, the anonymous users are shown with the name they entered, but with an additional name part /Guest which identifies them as anonymous users.

Appendix C. Sample auction scenario

383

Figure C-2 Auctioneers view

You can also see that the auction has not yet been started, and that the Start button is available while the Call button (One-Two-Sold) is not. Authenticated users Tom and Jim use the AuctionCustomer applet, which lists all other users in the auditorium. Since the auction has not been started, the Bid button is disabled. Figure C-3 shows Toms browser window.

Figure C-3 Authenticated customers view

384

Working with the Sametime Client Toolkits

Anonymous users Frank and Sam use the same applet as the authenticated users do, but the section they entered is different, so the title of their awareness list is different. Their application is shown in Figure C-4.

Figure C-4 Anonymous users view

Auction
Now we want to walk you through the auction itself. First, the auctioneer uses his send message function to send text messages to all auction participants - he wants to let the users know that the auction will start very soon.

Appendix C. Sample auction scenario

385

To start the auction, the auctioneer clicks the Start button and the auction can begin.

The new auction status is reflected in the transcript of all auction participants. Additionally, now some other functions become available. For the auctioneer, the button labeled One, which is used to call the auction, is now activated.

The authenticated customers now can use the amount field and the Bid button to send a bid to the auctioneer.

386

Working with the Sametime Client Toolkits

Immediately after the bid was sent, the auctioneers application decides if the bid is accepted or not (for example, if the amount was lower than the current bid it would not be accepted). Here you can see Jims transcript window showing that his bid is accepted.

The current bid is not only visible on the transcript, it also is shown in the auction status area.

Sam, who is still watching the auction as an anonymous user, is now motivated and wants to bid. He clicks the Logout button, then he logs into the auction with his user name and password. The auctioneer sees how someone leaves the anonymous section and how Sam enters the auditorium section.

Appendix C. Sample auction scenario

387

Sam is now able to send his bid to the auctioneer. He goes for 1300.

Sams bid appears on the transcript as all other users bids before.

The auctioneer now starts to call, so he clicks on the button labeled One. The call becomes visible as the auction status, and on the transcript.

388

Working with the Sametime Client Toolkits

But Jim Jackson bids again for 1400. The status is switching back.

Now some time goes on, and no new bids come in. The auctioneer calls One, Two, by clicking the appropriate buttons.

Finally, the auctioneer clicks on the button now labeled Sold. The transaction appears on the transcript.

Appendix C. Sample auction scenario

389

The auctioneer can still use the message window to send messages to the auction users.

Finally, the auctioneer presses the button labeled Stop. The auction now moves on to the next item.

The same bidding sequence goes on again. This concludes our walkthrough of the sample scenario.

390

Working with the Sametime Client Toolkits

Appendix D.

Sametime portlets
Attention:

The contents of this appendix are based on WebSphere Portal Server 2.1, and will not work on newer versions of WebSphere Portal Server without modification. The newer releases of the WebSphere Portal Server, version 4.1 and above, have an entirely new Portlet API. Additionally, they have a built-in collaborative components API, which allows one to more easily create Sametime-aware portlets. Redbooks about the new technologies in WebSphere Portal 4.1 are available. See http://www.redbooks.ibm.com for more information. Sametime capabilities can be added to a portal to offer the user of the portal awareness and real-time communication capabilities. In this appendix we include two Sametime portlet examples for the WebSphere Portal Server. These samples are courtesy of Christian Steege of IBM Switzerland. Christian is a co-author of the redbook Domino and WebSphere Together, SG24-5955. The samples illustrate: Opening the Java Sametime Connect client by token (thus not requiring the user to authenticate again).

Copyright IBM Corp. 2002. All rights reserved.

391

Launching a PlaceAwareness applet that makes the users enter a specified place and then displays all users in that place.
Note: For the purpose of this discussion, we assume knowledge of WebSphere Portal Server, or at least portlets in general, as well as some Lotus Domino knowledge.

Authentication by token
The Sametime portlet applications log into Sametime by token. They get the token from a Domino database on the Sametime server. That Domino database is a modified version of the stautht.nsf we describe in 7.6.1, Integrating with a Domino application on page 164. A form has been added to the Domino database that allows an authenticated user to get his or her token by the HTTP command:
http://<sametime server>/stapp.nsf/GetUserAndToken?OpenForm

This URL returns a page from which the token can be parsed out.

Using a Domino database as applet container


Besides having functionality to accept an HTTP command and return a Sametime token, the Domino database serves a few other purposes. It stores the actual Sametime applets: Sametime Java Connect and PlaceAwareness Applet. In addition it has the following forms: Connect - This form is invoked by the Sametime Java Connect portlet. It gets the token that is passed as a parameter and constructs the HTML Applets tags required to launch the Sametime Connect applet. GetUserAndToken - This form is invoked by the portlets. It in turn invokes a Sametime/Domino agent that gets the Sametime token for the current user and returns it to the portlet for parsing. PlaceAwareness - This form launches the PlaceAwareness applet. The name of the place to monitor is passed as a parameter in the URL.

392

Working with the Sametime Client Toolkits

Opening the Java Sametime Connect client


The portlet shown in Example D-1 on page 393 gets information about the Sametime server and so on from the WebSphere Portal Server configuration (specified in the XML file for the portlet). It gets the Sametime token described previously and creates a URL command on the fly that launches the Sametime Java Connect client. The Connect client is opened in its own window. This is accomplished by getting JavaScript for opening a new window from a JP file named openstwin.jsp. The URL to launch in the new window is a form named Connect in the Domino database where the token has been added as a parameter. On the Domino form, information about applet name, server, token, and so on is formatted into the correct tag structure to launch the applet.

Figure D-1 Sametime Java Connect portlet

Figure D-1 shows an example of the launched Java Connect client.


Example D-1 Sametime Connect portlet
// Java classes import java.io.*; import java.util.*; import java.net.*; // Jetspeed classes import org.apache.jetspeed.portlet.*;

Appendix D. Sametime portlets

393

import org.apache.jetspeed.portlets.*; import org.apache.jetspeed.portletcontainer.*; import org.apache.jetspeed.portlet.service.ContentAccessService; // IBM SSO Classes import com.ibm.wps.sso.*; public class CallSametimeConnect extends AbstractPortlet { private private private private private String String String String String m_sSTServerName = ""; m_sSTDbPath = ""; m_sSTForm = ""; m_sSTPlace = ""; m_sUser = "";

public void doView(PortletRequest req, PortletResponse res) throws PortletException, IOException { PrintWriter out = res.getWriter(); // add userid and password to request String sBasicAuth = getBasicAuth (req); String sSTUserAndToken = getSTUserAndToken(sBasicAuth); String sURL = "http://" + m_sSTServerName + "/" + m_sSTDbPath + "/" + m_sSTForm + "?OpenForm"; if (!sSTUserAndToken.equals ("")) sURL = sURL.concat ("&" + sSTUserAndToken); // include Java script that opens the applet window this.getPortletConfig().getContext().include ("/sametime/openstwin.jsp", req, res); // print applet tags and link to open the st window out.println ("<SCRIPT Language=\"JavaScript\">"); out.println ("var sURL = \"" + sURL + "\";"); if (!sSTUserAndToken.equals("")) { out.println ("openSTClient();"); } out.println ("</SCRIPT>"); out.println ("<B><I><FONT FACE=\"Arial,Helvetica\" COLOR=\"#3333FF\" SIZE=-1>"); out.println ("<A HREF=\"javascript:openSTClient();\">Launch Now</A>"); } private String getBasicAuth(PortletRequest req) { String sAuthUser = getUserLogin (req, false); String sAuthPw = getUserLogin (req, true);

394

Working with the Sametime Client Toolkits

if (sAuthUser == null || sAuthPw == null) { return ""; } else { String sAuth = sAuthUser + ":" + sAuthPw; sAuth = com.ibm.ejs.security.util.Base64Coder.base64Encode(sAuth); sAuth = "Basic " + sAuth; return sAuth; } } private String getSTUserAndToken(String sBasicAuth) { try { if (sBasicAuth.equals ("")) { return ""; } else { URL url = new URL("http://" + m_sSTServerName + "/" + m_sSTDbPath + "/GetUserAndToken?OpenForm"); HttpURLConnection con = (HttpURLConnection) url.openConnection(); // Set our Basic Auth Header con.setRequestProperty("authorization", sBasicAuth); con.connect(); // Get the Response Code String sMessage = con.getResponseMessage(); int iResCode = con.getResponseCode(); if (HttpURLConnection.HTTP_OK == iResCode) { Object objPage = con.getContent(); String sSTUserAndToken = ""; if (objPage != null) { BufferedInputStream bufIn = new BufferedInputStream(con.getInputStream()); int c; while ((c=bufIn.read()) >= 0) { if (!sSTUserAndToken.endsWith ("</STUserAndToken>")) { sSTUserAndToken = sSTUserAndToken.concat (new Character((char)c).toString()); if (sSTUserAndToken.endsWith ("<STUserAndToken>")) sSTUserAndToken = ""; } } bufIn.close(); } if (sSTUserAndToken.length() > 17) { sSTUserAndToken = sSTUserAndToken.substring(0, sSTUserAndToken.length() - 17); }

Appendix D. Sametime portlets

395

return sSTUserAndToken; } else { return ""; } } } catch (Exception e) { return ""; } } private String getUserLogin(PortletRequest req, boolean bPW) { try { if (req.getSession().getUser() == null) { return null; } else { UserImpl userCurrent = (UserImpl) req.getSession().getUser(); Set setUser = null; if (bPW) { setUser = userCurrent.getSubject().getPrincipals(Class.forName ("com.ibm.wps.sso.PasswordCredential")); PasswordCredential pwUser = null; if (setUser != null) pwUser = (PasswordCredential) setUser.toArray()[0]; if (pwUser == null) { return null; } else { return pwUser.getName(); } } else { setUser = userCurrent.getSubject().getPrincipals(Class.forName("com.ibm.wps.sso.UserDNPri ncipal")); UserDNPrincipal dnUser = null; if (setUser != null) dnUser = (UserDNPrincipal) setUser.toArray()[0]; if (dnUser == null) { return null; } else { String sName = dnUser.getName(); // name translation if (m_sUser.compareTo ("WPS") == 0) { // standard wps installation int iFrom = sName.indexOf ("="); int iTo = sName.indexOf (","); if (iFrom > -1 && iTo > -1 && iFrom < iTo) { sName = sName.substring (iFrom + 1, iTo); } } return sName;

396

Working with the Sametime Client Toolkits

} } } } catch (ClassNotFoundException e) { return ""; } } public void init(PortletConfig conf) throws UnavailableException { super.init (conf); m_sSTServerName = getPortletConfig().getAttribute("stserver"); m_sSTDbPath = getPortletConfig().getAttribute("stdbpath"); m_sSTForm = getPortletConfig().getAttribute("stform"); m_sUser = getPortletConfig().getAttribute("getuser"); if (m_sUser == null) m_sUser = "";

} }

Place awareness portlet


The portlet code shown in Example D-2 on page 398 gets a place name and constructs an applet tag on the fly by combining the place name with other applet parameters read from the PlaceAwareness form in the Domino database described in Using a Domino database as applet container on page 392. This launches a PlaceAwarenessList applet, which you can see the source code for in PlaceAwarenessList applet on page 401. Figure D-2 shows an example of this portlet.

Appendix D. Sametime portlets

397

Figure D-2 Place awareness portlet Example D-2 Place awareness portlet
// Java classes import java.io.*; import java.util.*; import java.net.*; // Jetspeed classes import org.apache.jetspeed.portlet.*; import org.apache.jetspeed.portlets.*; import org.apache.jetspeed.portletcontainer.*; import org.apache.jetspeed.portlet.service.ContentAccessService; // IBM SSO Classes import com.ibm.wps.sso.*; public class CallSametimeDomPage extends AbstractPortlet { private String m_sSTServerName = ""; private String m_sSTDbPath = ""; private String m_sSTForm = "";

398

Working with the Sametime Client Toolkits

private String m_sSTPlace = ""; private String m_sUser = ""; public void doView(PortletRequest req, PortletResponse res) throws PortletException, IOException { PrintWriter out = res.getWriter(); // add userid and password to request String sAuth = getBasicAuth (req); // print applet tags out.println (getAppletTags (sAuth)); } private String getAppletTags(String sBasicAuth) { try { URL url = new URL("http://" + m_sSTServerName + "/" + m_sSTDbPath + "/" + m_sSTForm + "?OpenForm&Place=" + m_sSTPlace); HttpURLConnection con = (HttpURLConnection) url.openConnection(); // Set our Basic Auth Header con.setRequestProperty("authorization", sBasicAuth); con.connect(); // Get the Response Code String sMessage = con.getResponseMessage(); int iResCode = con.getResponseCode(); if (HttpURLConnection.HTTP_OK == iResCode) { Object objPage = con.getContent(); String sAppletTags = ""; if (objPage != null) { BufferedInputStream bufIn = new BufferedInputStream(con.getInputStream()); int c; while ((c=bufIn.read()) >= 0) { if (!sAppletTags.toLowerCase().endsWith ("</applet>")) { sAppletTags = sAppletTags.concat (new Character((char)c).toString()); if (sAppletTags.toLowerCase().endsWith ("<applet")) sAppletTags = "<applet"; } } bufIn.close(); } return sAppletTags; } else {

Appendix D. Sametime portlets

399

return "<P>Unable to connect!, HTTP Response Code = " + iResCode +", HTTP Response Message = \"" + sMessage + "\"<BR>"; } } catch (Exception e) { return "<P>Exception: " + e.toString() + "<BR>"; } } private String getBasicAuth(PortletRequest req) { String sAuth = getUserLogin (req, false) + ":" + getUserLogin (req, true); sAuth = com.ibm.ejs.security.util.Base64Coder.base64Encode(sAuth); sAuth = "Basic " + sAuth; return sAuth; } private String getUserLogin(PortletRequest req, boolean bPW) { try { UserImpl userCurrent = (UserImpl) req.getSession().getUser(); Set setUser = null; if (bPW) { setUser = userCurrent.getSubject().getPrincipals(Class.forName ("com.ibm.wps.sso.PasswordCredential")); PasswordCredential pwUser = null; if (setUser != null) pwUser = (PasswordCredential) setUser.toArray()[0]; if (pwUser == null) { return ""; } else { return pwUser.getName(); } } else { setUser = userCurrent.getSubject().getPrincipals(Class.forName("com.ibm.wps.sso.UserDNPri ncipal")); UserDNPrincipal dnUser = null; if (setUser != null) dnUser = (UserDNPrincipal) setUser.toArray()[0]; if (dnUser == null) { return ""; } else { String sName = dnUser.getName(); // name translation if (m_sUser.compareTo ("WPS") == 0) { // standard wps installation int iFrom = sName.indexOf ("="); int iTo = sName.indexOf (","); if (iFrom > -1 && iTo > -1 && iFrom < iTo) { sName = sName.substring (iFrom + 1, iTo); }

400

Working with the Sametime Client Toolkits

} return sName; } } } catch (ClassNotFoundException e) { return ""; } } public void init(PortletConfig conf) throws UnavailableException { super.init (conf); m_sSTServerName = getPortletConfig().getAttribute("stserver"); m_sSTDbPath = getPortletConfig().getAttribute("stdbpath"); m_sSTForm = getPortletConfig().getAttribute("stform"); m_sSTPlace = getPortletConfig().getAttribute("stplace"); m_sUser = getPortletConfig().getAttribute("getuser"); if (m_sUser == null) m_sUser = ""; } }

PlaceAwarenessList applet
In Example D-3 you can see the source code for the Sametime applet that is launched by the portlet shown in Example D-2 on page 398. The applet enters the user into the specified place and shows a list of all users in that place.
Example D-3 PlaceAwarenessList applet
import java.applet.*; import java.awt.*; import java.awt.event.*; import import import import import import import com.lotus.sametime.core.comparch.STSession; com.lotus.sametime.core.comparch.DuplicateObjectException; com.lotus.sametime.awarenessui.placelist.PlaceAwarenessList; com.lotus.sametime.awarenessui.av.AVController; com.lotus.sametime.community.*; com.lotus.sametime.places.*; com.lotus.sametime.core.constants.EncLevel;

public class PlaceAwareness extends Applet implements LoginListener {

Appendix D. Sametime portlets

401

private private private private boolean

STSession m_sesST; String m_sPlaceName = ""; PlaceAwarenessList m_stPlaceAwarenessList; Place m_stPlace; m_bLogin = false;

public void destroy() { if (m_bLogin) { CommunityService stComm = (CommunityService) m_sesST.getCompApi(CommunityService.COMP_NAME); m_stPlace.leave(0); stComm.logout(); m_sesST.stop(); m_sesST.unloadSession(); } } public void init() { try { // generate a new session with a unique name System.out.println ("starting Place Awareness List " + this); m_sesST = new STSession("Place Awareness List " + this); // Call the session to load all available components m_sesST.loadAllComponents(); m_sesST.start(); setLayout(new BorderLayout()); // create the new list view m_stPlaceAwarenessList = new PlaceAwarenessList(m_sesST, true); add(m_stPlaceAwarenessList, BorderLayout.CENTER); m_sPlaceName = getParameter ("placeName"); // The default right-click menu for the awareness list does not // give audio & video as options. We can change that by // changing the controller to a different one. AVController avController = new AVController(m_stPlaceAwarenessList.getModel()); m_stPlaceAwarenessList.setController(avController); // login to the community login();

402

Working with the Sametime Client Toolkits

} catch(DuplicateObjectException e) { // This exception is thrown if an STSession with the same // name has already been created. System.out.println ("Duplicate Session!!"); e.printStackTrace(); } } /** * Login event. */ public void loggedIn(LoginEvent event) { //Get refernce to the place service PlacesService placesService = (PlacesService) m_sesST.getCompApi(PlacesService.COMP_NAME); //Create a new place object //System.out.println ("Enter place " + m_sPlaceName); m_stPlace = placesService.createPlace(m_sPlaceName, m_sPlaceName, EncLevel.ENC_LEVEL_RC2_40, 0); //bind the list to the specified place. m_stPlaceAwarenessList.bindPlace(m_stPlace); //enable enter/leave button //m_button.setEnabled(true); m_stPlace.enter(); m_bLogin = true; } /** * Logout event */ public void loggedOut(LoginEvent event) { } /** * Login to the community using the user name and password * parameters from the html. */ private void login() { // get a reference to the community service. We use the session // object which contains a reference to all the components that // were loaded to get a reference to the community service. CommunityService stComm = (CommunityService)

Appendix D. Sametime portlets

403

m_sesST.getCompApi(CommunityService.COMP_NAME); // register a listener to the login/logout events. stComm.addLoginListener(this); // login to the community //System.out.println (getParameter("loginName") + "/" + getParameter("loginToken")); stComm.loginByToken(getCodeBase().getHost(), getParameter("loginName"), getParameter("loginToken")); // Wait for the loggedin() event to enter the place } }

404

Working with the Sametime Client Toolkits

Sample files
The samples described in this appendix are available for download. See Appendix E, Additional Web material on page 407 for instruction on how to get the samples included in the 6666portlets.zip file. Table D-1 describes the files in 6666portlets.zip
Table D-1 Content of 6666portlets.zip
File name stconnect.par Description Portlet for Sametime Java Connect. It contains the Sametime toolkit jar, an XML config file, and the JSP to launch the connect client in a separate window. Portlet for PlaceAwareness applet. It contains the Sametime toolkit jar and an XML config file. JSP for launching Sametime Java Connect. It is also included with stconnect.par. Domino database to provide the Sametime token. Is also contains the Sametime applets and forms to launch those applets. Java source for the Sametime Java Connect portlet. Java source for the Sametime Place awareness portlet. Java source for the Sametime Place awareness applet.

wih.par openstwin.jsp stapp.nsf

CallSametimeConnect.java CallSametimeDomPage.java PlaceAwareness.java

Appendix D. Sametime portlets

405

406

Working with the Sametime Client Toolkits

Appendix E.

Additional Web material


This redbook refers to additional material that can be downloaded from the Internet as described below. The additional Web material files are described in Table E-1.
Table E-1 Additional Web material
File name 6666qsapplet.zip Description This is a zipped file with the Java source in a jar file for the two simple applets described in Chapter 5, Introduction to Sametime Java applets on page 89. It also includes a second version of the PlaceQuickStart applet where inner classes are used as listeners. In addition, the jar file contains the compiled classes, and test HTML files are included as well. This zip file includes Java source and compiled classes in a jar file for the Auction house sample described in Chapter 6, A place-based auction example on page 101. It also contains the HTML files to launch the two clients, as well as Image files for the sample auction items. Appendix B, Working with the auction house sample material on page 375 describes how to install this application. This zip file contains JavaDoc for the Auction house sample that can be viewed with a Web browser.

6666auctionapp.zip

6666auction-javadoc.zip

Copyright IBM Corp. 2002. All rights reserved.

407

File name 6666auction-java2html.zip

Description This zip file contains the Java source for the Auction house sample in HTML format that can be viewed with a Web browser. This zip file contains the final sample from Chapter 7, Customized chat UI applet on page 137, both in source and executable format. This zip file contains the resulting Domino database embedding a Sametime applet as described in 7.6.1, Integrating with a Domino application on page 164. This zip file contains the source for the sample described in Chapter 9, A complex meetings sample on page 207, as well as a compiled version of the sample. This zip file contains a compiled version of the sample described in Chapter 10, Using the C++ toolkit in Win32 programs on page 297. This zip file contains the Visual Basic source for the three steps we go through in the sample in Chapter 11, The COM toolkit on page 309. This zip file contains the two portlets described in Appendix D, Sametime portlets on page 391.

6666custui.zip

6666custuidomino.zip

6666cpp-meeting.zip

6666win32.zip

6666com.zip

6666portlets.zip

Locating the Web material


The Web material associated with this redbook is available in softcopy on the Internet from the IBM Redbooks Web server. Point your Web browser to:
ftp://www.redbooks.ibm.com/redbooks/SG246666

Alternatively, you can go to the IBM Redbooks Web site at:


ibm.com/redbooks

Select the Additional materials and open the directory that corresponds with the redbook form number, SG246666.

408

Working with the Sametime Client Toolkits

Related publications
The publications listed in this section are considered particularly suitable for a more detailed discussion of the topics covered in this redbook.

IBM Redbooks
For information on ordering these publications, see How to get IBM Redbooks on page 410.

Lotus Sametime 2.0 Deployment Guide, SG24-6206 B2B Collaborative Commerce with Sametime, QuickPlace and WebSphere Commerce Suite, SG24-6218 Applying the Patterns for e-business to Domino and WebSphere Scenarios, SG24-6255 Lotus Mobile and Wireless Solutions, SG24-6525 Customizing QuickPlace, SG24-6000 Domino and WebSphere Together, SG24-5955 COM Together with Domino, SG24-5670 Lotus Domino Release 5.0: A Developer's Handbook, SG24-5331 iNotes Web Access Deployment and Administration, SG24-6518 Inside the Lotus Discovery Server, SG24-6252 XML Powered by Domino How to use XML with Lotus Domino, SG24-6207 Using VisualAge for Java to Develop Domino Applications, SG24-5424 Connecting Domino to the Enterprise Using Java, SG24-5425 Performance Considerations for Domino Applications, SG24-5602 Using Domino Workflow, SG24-5963

Referenced Web sites


These Web sites are also relevant as further information sources:

Copyright IBM Corp. 2002. All rights reserved.

409

The developers corner of the Sametime Web site. Here you can download toolkits, beta version, browse technical documents, and participate in the Sametime developers discussion forum.
http://www.lotus.com/sametimedevelopers

Lotus Developer Network is Lotus primary destination for the latest developer information and resources. It contains articles about new and current technologies, along with relevant tips and techniques to help you build dynamic collaborative e-business applications.
http://www.lotus.com/developer/

Notes.net from Iris, the developers of Notes and Domino, is a technical Web site with discussion forums, documentation, and the Webzine Iris Today, with many good articles about technical details of Domino.
http://notes.net/

The IBM developerWorks Web site is designed for software developers, and features links to a host of developer tools, resources, and programs.
http://ibm.com/developer/

Lotus Supports Web site - Search using keywords or browse the Lotus Knowledge Base and locate helpful and informative tech notes and technical papers for the entire Lotus Product family. This source of information contains the latest technical information updated hourly.
http://support.lotus.com/

Entry point to information about the IBM WebSphere software platform for e-business:
http://ibm.com/websphere/

How to get IBM Redbooks


Search for additional Redbooks or Redpieces, view, download, or order hardcopy from the Redbooks Web site:
ibm.com/redbooks

Also download additional materials (code samples or diskette/CD-ROM images) from this Redbooks site. Redpieces are Redbooks in progress; not all Redbooks become Redpieces and sometimes just a few chapters will be published this way. The intent is to get the information out much quicker than the formal publishing process allows.

410

Working with the Sametime Client Toolkits

IBM Redbooks collections


Redbooks are also available on CD-ROMs. Click the CD-ROMs button on the Redbooks Web site for information about all the CD-ROMs offered, as well as updates and formats.

Related publications

411

412

Working with the Sametime Client Toolkits

Index
A
Abstract Window Toolkit See AWT Access list place 56 stage section 56 Activity adding to place 286 in place 53 managing 232 ADA compliance 11 Adapter 26 Add Tools dialog 279 Anonymous login 31 Anonymous users deployment considerations 371 Applet connections over Internet 372 deployment considerations 163 entering a Sametime place 95 passing token 183 running in VisualAge for Java 86 subclass from STApplet 372 with Sametime code 89 Application sharing 38 Architecture C++ toolkit 200 complex meetings sample 212 places 49 Sametime 18 Attribute types 46 Attributes adding to place 286 in auction house sample 129 in place 54 listening for changes 65 setting in place 64 Auction house sample application flow 107 bid from cell phone 134 changing attributes 129 class diagram 115 event flows 124 event listeners and adapters 117 implementation 114 Java2HTML 377 JavaDoc 376 objects in application 106 overview 102 real life model 102 requirements 104 scenario 381 sending text/data 128 the client applications 110 user interface classes 119 working with 375 Audio activity 233 Audio over IP 38 Audio/Video wizard 241 Authentication 31 by token 189, 392 Sametime Links toolkit 364 Automatic nicknames 35 Awareness 4 attributes 32 place-based 51, 360 Awareness service 32 AWT 37

B
Broadcast 39 See also Streamed media Buddy list sample instant messaging type supported 347

C
Cell phone as Sametime client 134 Chat 4, 276 customizing window 138 Chat activity 233 Chat meeting 209 Sametime Links toolkit 359 window 222 Chat room Sametime Links toolkit 361

Copyright IBM Corp. 2002. All rights reserved.

413

chat window Sametime Links toolkit 358 Class diagram for auction house sample 115 Classpath for JDK 74 in VisualAge for Java 82 Client toolkits See Toolkits Codebase Sametime Links toolkit 364 Communication in place 54 Community service 31 Community services figure 29 COMP_NAME 41 Components COMP_NAME 41 loading 40 STBase 40 Controller 20 See also Model-View-Controller Core types 42 attributes 46 importing 42 STAttribute 46 STExtendAttribute 46 STGroup 45 STId 43 STLoginId 43 STObject 44 STObjectImpl 44 STServer 45 STUser 45 STUserInstance 46 CustomizeChatUI how to enable in other components 182 Customized chat UI sample 137

Domino 36 LDAP 36 Directory service 35 Domino as applet container 164 enabling database for Sametime applet 171 Sametime Discussion template 169 Domino directory 36

E
Error handling 98 Event definition 23 Event-based programming 22 adapter 26 event 23 listener 23 subscription 25 Existential attribute 47 Extend versus implement 28 Extranet support Sametime Links toolkit 357

G
Group 45

H
Heavy attribute 47 HTML chat window 358 Sametime Links toolkit 355 source code for auction house sample 378 HTTP tunneling Sametime 372

I
IBM VisualAge for Java and Sametime Java toolkit 79 classpath 82 exporting code 86 importing Sametime samples 81 object hierarchy view 116 passing parameters to program 84 running applet 86 setup 79 source code for auction house sample 378

D
Data transfer instant messaging 374 Deployment considerations 371 Deployment considerations applets 163 Directory

414

Working with the Sametime Client Toolkits

IM See Instant messaging Image loading from jar file 172 Implement versus extend 29 Infrastructure for anonymous users 371 Inner class 27 Instant messaging 5 and data transfer 374 type supported by client 347 Instant messaging service 34 Interface 25 definition 24 implement versus extend 29 using LoginListener 94 Internet and Sametime applets 372 IP audio and video 38

L
Late binding Sametime COM toolkit 315 LDAP 36 Listener 23 See also Nested class definition 25 in auction house sample 117 place messages 55 using LoginListener 94 Load time toolkit comparison 10 Login adding listener 41 anonymously 31 by password 31 by token 31, 34 Sametime community 40 STBase 40 using LoginListener interface 94 Lookup service 33 LTPA Sametime Links toolkit 364

J
Jar file 79 loading image from 172 Java extend and implement 28 inner class 27 nested class 27 Java Development Kit See JDK Java security policy 77 Java2HTML auction house sample 377 JavaDoc auction house sample 376 JavaScript accessing token 189 API in Sametime Links toolkit 357 Sametime Links toolkit 355 JDK classpath 75 compiling and running 76 installing 74 path 75 policy file 78

M
Meeting factory services 38 Meeting invitation dialog 260 Meeting room client 217 URL to launch 292 Meeting services 37 figure 29 Message loop Win32 program 304 MFC Sametime C++ toolkit library 304 versus Win32 298 Microsoft Foundation Classes See MFC Model 20 See also Model-View-Controller Model-View-Controller 20 MRC See Meeting room client

N
Names service 35 Nested class 27 Nicknames 35

Index

415

Notification See Listener N-Way chat See Chat meeting

O
Online meeting services 5

P
Path for JDK 74 Permissions in place 55 Persistent place 52 Place See also Place patterns activity 53 adding activities 232 adding activity 286 adding attributes 286 attributes 54 common pitfalls 132 communication 54 community span 56 creation modes 267 figure of places model 51 how to throw a user out 133 joining existing 267 name of 133 online auction Java sample 101 overview 50 permissions list 55 persistent 52 restricting access 56 scalability 56 section 53 setting attributes 64 stage section 53 text/data messages 54 Place patterns 57 changing section 61 entering a place 58 identifying sections 60 list of users in a section 63 listening for changed attributes 65 listening for messages sent to you 67 listening for place events 58 listening for section events 62

listening to users in section 63 sending messages 66 setting attributes 64 Places architecture 49 in auction house sample 127 Places service 33 Policy file for JDK 78 in VisualAge for Java 85 Portlet Java Sametime Connect 391 PlaceAwareness 392 Sametime 391 WebSphere Portal Server 391 Post service 36 Proxy objects 19 Proxy PAC file support 372 Public group 45

R
Redbooks Web site 410 Contact us xvi Resolve name 45 Restricting access to place 56 Runtime components Sametime Links toolkit 363

S
Sametime architecture 18 authentication 31 direct socket connection 372 enabling Domino database 170 events 18 HTTP connection 372 in Domino application 164 meeting center 38 Model-View-Controller 21 portlets 391 proxy objects 19 See also Toolkit services services 29 streamed media 38 toolkits - See Toolkits what is it 4 Sametime C++ toolkit available services 202

416

Working with the Sametime Client Toolkits

compared 11 in Win32 programs 297 layered architecture 200 libraries for MFC/Win32 304 message loop in Win32 program 304 overview 8 package 203 target platform 9 wmain 304 working with 199 Sametime COM toolkit adding tolkit reference to project 313 awareness service 311 community service 311 compared 11 getting it 312 instant messaging service 311 JavaScript in IE 310 late binding 315 lookup service 311 overview 8, 310 target platform 9 Visual Basic 310 Sametime Discussion template 169 Sametime Everyplace 134 Sametime Java toolkit and IBM VisualAge for Java 79 compared 11 compiling and running with JDK 76 customized chat window 138 enabling use of customized chat window 182 error constants 98 how to get 71 overview 8 services used in auction house sample 114 target platform 9 writing applets 89 Sametime Links toolkit adding a link 365 authentication considerations 364 chat rooms 361 codebase 364 compared 11 enabling Web application 363 features 356 overview 7, 355 runtime components 363 target platform 9 Sametime Meeting client

launching from C++ program 207 Sample auction house (place-based) 106 awareness (COM toolkit) 320 Buddy List (COM toolkit) 310, 342 complex meetings sample 207 CustomizeChatUI (user interface) 137 Java Sametime Connect portlet 391 login (COM toolkit) 316 online assistance (STLinks) 366 passing token between applets 183 place awareness portlet 392 PlaceQuickStart (basic place-based) 95 QuickStart (basic applet) 90 RedCustumizeChatUI (storage service) 173 Win32Status 298 Scalability place 56 Scenario auction house 381 Section 53 identifying 60 listening to users 63 moving to other sections 61 restricting access 56 setting attributes 64 stage 53 Service layer 200 Session creating 40 Single sign on Sametime Links toolkit 364 Skills required toolkit comparison 10 Stage section 53, 273 restricting access 56 STApplet 372 STAttribute 46 STBase 40 STError 98 STExtendAttribute 46 STGroup 45 STId 43 STLoginId 43 STObject 44 STObjectImpl 44 Storage service 34 Streamed media 38 STServer 45

Index

417

STUser 45 finding 45 STUserInstance 46 Subscription See Listener

T
Text/data messages in auction house sample 128 in place 54 Thread-safe C++ toolkit 201 Token expiry time 34 generating 290 passing between applets 183 SametimeSecretGenerator agent 34 use in portlet sample 392 Token service 34 Toolkit services activity 57 application sharing 38 awareness 32, 311, 358 broadcast 39 community 31, 311 core types 42 directory 35 figure 29 general features 30 instant messaging 34, 311, 358 loading components 40 lookup 33, 311 meeting 37 meeting factory 38 names 35 places 33 PlacesAdmin 57 post 36, 246 storage 34, 173 streamed media 38 token 34, 184, 290 used in auction house sample 114 whiteboard 38 Toolkits 7 ADA compliance 12 adapters 26 C++ 8 COM 8

comparison 11 features supported 9 interfaces 24 Java 8 load time 10 overview 7 Sametime Links 7 skills required 10 target platforms 9 which to use 8 Transport layer 200 Type instant messaging 347

U
URL for Sametime Meeting room client 292 User listening for messages in place 67 setting attributes in place 64 User interface classes in auction house sample 119

V
VBA Sametime COM toolkit 8, 310 Video activity 233 Video over IP 38 View 20 See also Model-View-Controller Virtual place See Place Visual Basic adding COM toolkit reference to project 313 Sametime COM toolkit 8, 310 VisualAge for Java policy file 85

W
Web application enabling with Sametime Links toolkit 363 WebSphere Portal Server Sametime portlet 391 Whiteboard service 38 Win32 message loop 304 Sametime C++ toolkit 297

418

Working with the Sametime Client Toolkits

Sametime C++ toolkit library 304 versus MFC 298

Index

419

420

Working with the Sametime Client Toolkits

Working with the Sametime Client Toolkits

(0.5 spine) 0.475<->0.875 250 <-> 459 pages

Back cover

Working with the Sametime Client Toolkits


Java, C++, COM and Sametime Links toolkits The Sametime Places architecture Many "real world" application samples
This IBM Redbook is for developers and architects who want to utilize Sametime functionality in applications based on Java, C++, COM, or HTML and JavaScript. We explore capabilities offered by the different Sametime client toolkits, which you can use to add functionality to existing applications and to create powerful new applications that enable real-time collaboration. We discuss event-based programming, Sametime services, and the Sametime Place architecture. As part of our discussion about the Java toolkit, we provide an online bidding application sample that utilizes the Sametime Places architecture, and a sample to customize the chat window supplied by the toolkit. Next we describe the Sametime C++ Toolkit, and build a full-blown Sametime Connect client in C++. We also discuss considerations for developing Win32 programs in C++. Finally, we describe the newest additions to the Sametime client toolkits: the Sametime COM Toolkit and the Sametime Links Toolkit. We develop a BuddyList application in Visual Basic, and discuss how easily the Sametime Links Toolkit can add Sametime functionality to Web pages without requiring more than basic skills in HTML and JavaScript. Sametime portlets for WebSphere Portal Server are included in an appendix. Most of the samples in this redbook are available in source format from the IBM Redbooks Web site.

INTERNATIONAL TECHNICAL SUPPORT ORGANIZATION

BUILDING TECHNICAL INFORMATION BASED ON PRACTICAL EXPERIENCE IBM Redbooks are developed by the IBM International Technical Support Organization. Experts from IBM, Customers and Partners from around the world create timely technical information based on realistic scenarios. Specific recommendations are provided to help you implement IT solutions more effectively in your environment.

For more information: ibm.com/redbooks

SG24-6666-00

ISBN 0738423920

S-ar putea să vă placă și