IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Lotus  >

Lotus Sametime 开发入门,第 2 部分: 使用服务器端 Toolkit 扩展 Sametime 服务器的功能

developerWorks
文档选项

未显示需要 JavaScript 的文档选项

样例代码


级别: 初级

刘 欣 (liuxinlx@cn.ibm.com), 软件工程师,IBM CSDL, IBM China Software Development Lab
常 红平 (changhp@cn.ibm.com), 软件工程师,IBM CSDL, IBM China Software Development Lab

2007 年 1 月 19 日

在该系列的 第一篇 文章中,我们介绍了 Lotus sametime 客户端 Toolkit 的主要服务和使用方法,并且开发了一个简单的聊天应用程序, 本篇文章作为 Lotus Sametime toolkit 开发入门系列的第二篇,将把重点转移到服务器端,主要介绍服务器端 Java Toolkit 的使用方法和重要的 API,并带领读者循序渐进的开发出一个简单的猜拳游戏。

Sametime 服务器端 toolkit 介绍

下表列出了服务器端的各种 toolkit,在版本 7.0 前这三个 API 是分开打包的,而版本 7.5 将这三个 API 合了在一起。

版本用途和使用环境
Sametime Community Server toolkit一套 Java 的 API,用来加强 Sametime 的功能和服务
Sametime Directory and Database Access toolkit一套 C 的 API,用来定制对已存在的 Sametime 目录服务器或数据库的访问
Sametime Telephony toolkit用来集成电话会议功能

其中本文 Community Server toolkit 是最为常用的工具包。本文将只对版本 7.0 Community Server toolkit 进行介绍。下文中如果没有特殊说明,当提到 toolkit 时,均是指版本 7.0 Community Server toolkit。





回页首


Sametime community Server toolkit 简介

Sametime community toolkit 是 Sametime java client toolkit 的超集,它提出了一个新的概念: Server Application,表示在 Sametime community 中的一个功能或者服务。 Sametime 服务器本身的绝大部分功能都是由 Server Application 构成的。

通过 Community Server Toolkit,开发人员能够开发满足特定需求的 Server Application, 注册到 Sametime 社区中,成为其中的“一等公民”,从而对外提供服务。





回页首


Sametime community 体系结构

一个 Sametime community 包括如下四种 community 成员:

  • 客户端(Clients):是一个以用户身份使用 TCP/IP 协议登录到 community 的程序。客户端有用户界面。
  • 多路复用器(Multiplexers):通过集中 I/O 访问提高 Sametime 的稳定性。多路复用器对于客户端是透明的。
  • Community 集线器(Community Hub):是 Sametime community 的核心,它负责管理 community 的参与者(客户端,多路复用器和服务器应用程序),在各个 community 成员间路由信息,并负责通知事件的接收者。Community 集线器可以有一个或多个。
  • 服务器应用程序(Server Application):Sametime 的绝大多数功能都是由服务器应用程序提供的,其它少部分由 Sametime 内核组件提供。服务器应用程序使用 TCP/IP 协议直接连接到 Community 集线器。

下面是一个 Sametime community 的结构图:


图1:Sametime community 体系结构
图1:Sametime community 体系结构

Community 中的信息路由依赖于一种称为信道(Channel)的虚拟连接。一条信道可能会跨越多个 TCP/IP 连接。例如下面的例子,该信道跨越了 4 个 TCP/IP 连接。


图2:一个跨越 4 个 TCP/IP 连接的信道
图2:一个跨越 4 个 TCP/IP 连接的信道

服务器应用程序实现了 Community 服务器的各项功能。一个服务器应用程序可以是一个或多个服务(Service)的容器。而一个服务也可以被包含在一个或多个服务器应用程序中。Sametime Community 中内置的主要服务器应用程序包括:

  • 配置(Configuration):定时从 Sametime 配置数据库读取配置信息并且分发到相应 Community 参与者。
  • 用户感知(Awareness 或 Buddy List):感知 Community 中的其他用户的状态。
  • 认证(Authentication):用户认证是针对 community directory 实现的。 用户认证可以有多种方式
  • 目录(Directory):提供 Sametime 目录浏览功能,通常用来解析或查找用户。
  • 用户数据存储(User Storage):负责在服务器上存储用户相关数据,如用户通用属性和私有属性。
  • 日志(Logging):负责将 Community 服务器中的活动信息记入日志。包括普通的服务器活动和用户间的交谈内容。
  • 空间(Places):提供空间级(place-based)的用户感知和交流工具。
  • 在线目录(Online directory):负责在整个 community 的多个 community hub 间中维护一个一致的用户状态快照(如谁当前在线,登录到哪个 hub,哪个 place 等)。

这些服务器应用程序相互配合构成了 Sametime 服务器的主要功能。而用户在使用 Sametime 客户端应用程序时不会感觉到它们的存在。如果要开发自己的服务器应用程序,我们需要熟悉 toolkit 中的各种服务。

Sametime Community toolkit 提供的主要服务包括:

  • 服务器应用程序服务(Server application service):使用 toolkit 编写任何服务器应用程序都要用到这个服务。我们可以通过该服务以一个服务器应用程序的身份登录到 Sametime 服务器,注册或注销服务类型。
  • 信道服务(Channel service):提供通过 Sametime 交流的协议。一个服务器应用程序在 Sametime 服务器上注册了它的服务类型后,Sametime 服务器会把所有打开信道的申请转发到该服务器应用程序。一但信道被打开后,服务器应用程序就可以使用该信道与其他客户端交流了。
  • Community 事件服务(Community events service):当事件发生时,负责通知用户或服务器应用程序。这些事件包括:
    • 用户登录
    • 登录失败
    • 服务启动或停止
    • 用户状态变化
    • 用户私有列表变化
    • 用户上线或下线
    • 用户存储(storage)变化
  • 通用感知服务(General awareness service):用来设置或删除 Sametime Server 的一些属性(如是否支持音频、视频等)。
  • 空间管理服务(Places admin service):用来管理空间服务器应用程序。如创建空间,管理空间的特性等。
  • 空间活动服务(Places activity service):用来编写 Sametime 空间的活动提供者(activity provider)。活动(activity)是一个在空间中运行的程序,该程序是空间中所有成员都可见的。活动提供者可以执行一系列的任务,如监视空间中消息,控制用户等。
  • 服务器应用程序存储服务(Server application storage service):用来把用户相关的信息作为属性直接存储到Sametime服务器中。我们自己的服务器应用程序可以使用这个服务存取标准的 Sametime 属性或应用程序特定的属性。
  • 轻量级登录服务(Light login service):允许一个多路复用器应用程序(MUX application)向服务器同时传输多个连接。多路复用器应用程序可以作为一个客户端网关来实现轻量级登录。
  • 服务器应用程序证明服务(Server application token service):用来生成一个作为用户登录到 Sametime 的证明(token)。这个服务在一个应用程序想要一个用户身份登录时非常有用。




回页首


开发 Sametime 服务器端应用程序

限于篇幅,本文不可能涉及 Sametime Community toolkit 中的所有功能。本文将随着介绍服务器 toolkit 中的最重要服务带领读者完成一个简单的猜拳游戏(finger-guessing game)。有兴趣的读者可以自行阅读本文列举的参考资料和服务器端 toolkit 自带的其他示例程序。

这个猜拳游戏所涉及到的服务包括:

  • 服务器应用程序服务
  • Community事件服务
  • 空间管理服务
  • 空间活动服务

该程序客户端界面如下图所示。


图3:猜拳游戏客户端界面
图3:猜拳游戏客户端界面

服务器端程序的界面比较简单,只提供一个“Stop Service”按钮,通过它可以删除在游戏中创建的空间。

我们先来看看这个游戏程序的功能:

  1. 玩家登录以后,可以从游戏桌 (desk0,desk1,desk2) 中任选一个,点击“Enter”进入该游戏桌,此时会有 3 种情况:
    1. 该游戏桌已经坐满了,当前玩家将无法进入,只能选择其他的游戏桌;
    2. 该游戏桌已经有领一个玩家在等待(猜拳游戏需要两个游戏者), 那么游戏立刻开始;
    3. 该游戏桌还没有任何人,此时当前玩家需要等待其他玩家;
  2. 游戏开始后,用户可以点击“Stone”,“Scissor”,“Paper”来猜拳,另一玩家出拳后,游戏的服务器端会给出胜负判断,把消息显示在下面的面板中。 一轮游戏结束。下一轮游戏开始。
  3. 玩家可以随时点击“Leave”离开当前的游戏桌,此时游戏随之中止。

在下面的章节中,本文将使用 Sametime Community Toolkit 中的相关服务来完成给猜拳游戏,为了便于读者理解这些服务的使用,本文中的代码只是从程序中摘取的一些片断并做了少许修改,完整的代码可以在参考资料中下载。

一、概述

猜拳游戏分为服务器端(FGServer)和客户端(FGClient)两个部分,分别使用了 Server toolkit 和 client toolkit,其中 FGServer 主要完成创建虚拟的游戏桌、检测用户事件、维持游戏桌的状态、判断游戏胜负等功能。FGClient 主要是完成进入游戏桌、在游戏桌中玩游戏等功能。

FGServer 的功能:

  1. 创建游戏桌

    猜拳游戏使用 Place 来模拟游戏桌,程序初始化时会使用 PlacesAdminService 创建 3 个缺省的 Place 作为游戏的场所。

    • 在创建 Place 的时候规定:每个 Place 只能有一个 Section,即 Stage(参见该系列的 第一篇 文章), 该 stage 只能容纳两名用户, 对于登录到游戏桌的用户,游戏会把他们放置到 Stage 中,如果 stage 已满,则不接受其他用户进入。
    • FGServer 对每个 Place 都添加一个 Activity, 用户发送给 FGServer 的消息都通过该 Activity 的监听器来接收。
  2. 检测用户事件
    • 进入/离开游戏桌:通过 Stage 的监听器来检测。
    • 用户发送的消息(猜拳):通过 Activity 的监听器来检测,我们把玩家发送的消息称为命令(Command), FGServer 会使用 CmdFactory 来解析这些命令。
  3. 维持游戏桌状态

    猜拳游戏用一个列表来记录进入到游戏桌的所有用户:

    • 每当有用户进入游戏桌时,猜拳游戏会检查游戏桌的状态:如果游戏桌没有坐满,当前玩家需要等待,否则游戏开始。
    • 当用户离开游戏桌时,游戏桌中的现有玩家就需要等待。
  4. 判断游戏胜负

    当两个玩家都出过拳以后,猜拳游戏会进行判断,给出胜负关系,发送给游戏桌中的玩家,然后重启下一轮游戏。为了方便扩展,猜拳游戏提取出了“规则”(Rule)的概念,根据当前的玩家的输入,进行计算和判断。

FGClient

猜拳游戏的客户端相对简单,除了提供一个简单的游戏界面以外,主要的操作是进入 Place,与 FGServer 进行消息交互。

  1. 发送消息

    登录到 Place 以后,FGClient 能够获得 Place 中的 Activity。所有发向服务器端的消息都通过 Activity 来进行。

  2. 接收消息

    进入 Place 以后,FGClient 可以获得当前用户在 Place 中的一个对象引用,称为 MySelfInPlace, 通过向该对象添加消息监听器,则可以获取所有发给自己的消息。其中以”@”开始的消息称为命令,当前只有两种命令: (1)@game start, (2) @game end FGClient 需要解析、执行这些命令来,最终的结果会反应的用户界面。对于普通的消息,FGClient 只是简单的显示。

二、登录到猜拳游戏和服务器端初始化

FGClient

游戏启动以后首先要做的是登录到猜拳游戏,实际上是登录到 Sametime Server,所使用的服务是 Sametime Client Toolkit 中的 CommunityService, 具体的使用方法请参考该系列的 第一篇 文章。

FGServer

步骤一:创建 Session 对象

略(参见该系列的 第一篇 文章)

步骤二:登录到 Sametime 社区

与 FGClient 所不同的是,FGServer 并不是 Sametime Server 的一个用户,所以登录的方式有所不同,需要使用 ServerAppService,该服务可以把 FGServer 这个新应用程序注册到 sametime 社区中,代码如下:


代码 1:登录 sametime 社区

//首先获取一个ServerAppServer 对象
ServerAppService saService = (ServerAppService) session
                .getCompApi(ServerAppService.COMP_NAME);
//声明FGServer是一个Server Application
short loginType = STUserInstance.LT_SERVER_APP;
//它所支持的服务是Constants.FINGER_GUESSING_ACTIVITY_TYPE
int[] supportedServices =
{ Constants.FINGER_GUESSING_ACTIVITY_TYPE };

//不通过MUX,直接连接到sametime社区中
Connection[] connections =
{ new SocketConnection(1516, 17000), };

saService.setConnectivity(connections);
//添加一个Listener,读者如果看过第一篇文章,对这种Listener的编程模型应该比较熟悉
saService.addLoginListener(new LoginHandler());
//注意这里的登录方式,是通过Server Application的方式登录
saService.loginAsServerApp(hostName, loginType, "FingerGuessing",
        supportedServices);

上面代码中 FINGER_GUESSING_ACTIVITY_TYPE 是一个自定义的活动类型编号。该编号必须是唯一的,即不能于 Sametime 内置的任何活动编号和其他用户自定义活动编号重复。

把我们自定义的活动加入 Place 有两种办法。一种是由客户端显式的调用方法 Place.addActivity(),一种是将该活动设置为 Place 的缺省活动,这样 Place 在创建时该活动就自动被加入了。我们在下面的步骤中使用第二种方法。

步骤三:初始化 Place

FGServer 作为服务器应用程序登录以后,最重要的工作就是初始化 Place,这一步的工作比较负杂,有多个事件的通知和处理,需要多个 Service 进行协作来完成。整个初始化流程如下图所示:


图4:初始化 Place
图4:初始化 Place

(1) 向 ActivityService 和 PlaceAdminService 添加 Listener


代码 2:添加 Listener

activityService.addActivityServiceListener(new ActivityServiceHandler());
placeAdminService.addPlacesAdminListener(new PlaceAdminHandler());

(2) 当 PlaceAdminService 准备好,可以使用时,系统发出事件通知,PlaceAdminHandler 的 serverAvailable 方法被调用


代码 3:设置缺省的 Activity 和 Section

public void serviceAvailable(PlacesAdminEvent event){
//设置一个缺省的 Activity,以后每当创建一个 Place 的时候,该 Activity 就会被创建
placeAdminService.setDefaultActivity(
                    Constants.FINGER_GUESSING_PLACE_TYPE,
                    Constants.FINGER_GUESSING_ACTIVITY_TYPE, null);
//猜拳游戏中,每个游戏桌只能容纳两个用户,这里通过 PlaceAdminService 来完成设置:
//一个 Place 只有一个 Section,每个 Section 只能允许两个用户进入。
placeAdminService.setDefaultSections(
            		Constants.FINGER_GUESSING_PLACE_TYPE,
					Constants.SECTION_AMOUNT, 
					Constants.SECTION_CAPACITY); 
}

上面代码中的FINGER_GUESSING_PLACE_TYPE是我们自定义的Place类型编号。该编号同样也必须是唯一的。

(3) 系统发出“设置缺省 Activity 成功”的事件,PlaceAdminHandler 的 defaultActivitySet 方法被调用


代码 4:创建 Place

public void defaultActivitySet(PlacesAdminEvent event){
	//创建三个持久化的Place
	for (int i = 0; i < Constants.PLACE_AMOUNT; i++)
	{
                placeAdminService.createPersistentPlace(
                        Constants.PLACE_NAME_PREFIX + String.valueOf(i),
                        Constants.PLACE_NAME_PREFIX + String.valueOf(i),
                        Constants.FINGER_GUESSING_PLACE_TYPE,
                        Constants.PLACE_PASSWORD, EncLevel.ENC_LEVEL_DONT_CARE);

	}
}

注意我们必须在设置缺省 Activity 成功事件触发后创建自己的 Place。否则无法确保我们自己的活动被加入到新创建的 Place。

(4) 创建 place 成功以后,系统向 ActivityService 发出一个事件,用来请求一个 activity


代码 5:处理 Request Activity 事件

//需要注意的是:下面的代码会执行三次,因为创建了三个 Place
public void activityRequested(ActivityServiceEvent event){
//获取 Activity 对象
MyActivity myActivity = event.getMyActivity();
//必须通过 ActivityServer 接受该 Activity
activityService.acceptActivity(myActivity, null);      
//我们终于获得了 Place 对象的引用,
Place p = event.getPlace();
//创建一个FGServerTable对象来封装该place
FGServerTable table = new FGServerTable( FGServer.this, p);
}

(5) 在 FGServerTable 中,添加 PlaceListener


代码 6:添加 PlaceListener

public FGServerTable(FGServer fg, Place place)
{
        this.fg = fg;
        this.place = place;
        this.place.addPlaceListener(new PlaceHandler());
}

至此为止,游戏桌的初始化全部完成,读者可以看出,费了这么多的周折,最重要的是要获取对 place 的引用,以便进行后续的操作。

三、进入或退出游戏桌

猜拳游戏使用 Toolkit 中的 Place 来模拟一个游戏桌,当用户进入/退出游戏桌时,实际上是进入/退出一个特定的 Place。

FGClient

每当用户在界面上选中一个游戏桌,点击”Enter”按钮时,FGClient 将会创建一个 FGClientTable 对象来代表该游戏桌,然后调用该对象的 enter() 方法:


代码7:进入游戏桌

currentTable = new FGClientTable(client, tableName);
currentTable.enter();

在enter方法中有如下步骤:

步骤一:创建并进入 Place


代码 8:进入 Place

currentPlace = placeService.createPlace(placeName, placeName,
                EncLevel.ENC_LEVEL_DONT_CARE,
                //指定place的类型,与server端创建时一致
                Constants.FINGER_GUESSING_PLACE_TYPE); 

currentPlace.enter(
  //该place的密码,由server端提供
Constants.PLACE_PASSWORD,      
//进入一个现有的place(place在server端已经创建)     
PlacesConstants.PLACE_CREATION_JOIN, 
//进入到stage中
true);      

步骤二:实现 PlaceListener

在 enter 方法之前增加语句:


代码 9

place.addPlaceListener(new PlaceHandler());

PlaceHandler 的实现如下:


代码 10:客户端 Place Listener

private class PlaceHandler extends PlaceAdapter
{
	public void entered(PlaceEvent event)
	{
	    Place p = event.getPlace();
	   	mySelfInPlace = p.getMyselfInPlace();
        // 添加一个Message Handler来接收从服务器端发送的消息
	    mySelfInPlace.addMyMsgListener(new MyMsgHandler());	 
 
        //已经成功的进入Place,调用client的相关方法来改变UI,比如Enable “Leave” 按钮
	    client.enterTable(getName());	
}
	
	public void enterFailed(PlaceEvent event)
	{  
        //进入place 失败, 可能是place已经满了,通知client更新UI
	    client.enterFailed(getName(), event.getReason());
	}
public void activityAdded(PlaceEvent event)
{
    //在此处能检测到server增加的Activity, 以后需要通过它向server发送消息
        activity = event.getActivity();
    }

}

步骤三:实现MyMsgListener


代码 11:Message Listener

private class MyMsgHandler implements MyMsgListener
{
    public void textReceived(MyselfEvent event)
	{
            String text = event.getText();
// 如果从server端收到的message是一个命令(以@开始的消息),则由CmdFactory进行处理
            if (CmdFactory.isCommand(text))
            {
                CmdBase cmd = CmdFactory.getInstance(text);
                cmd.processCmd(client, text);
            }
            else
            {
                // 这是一个普通消息,直接显示到界面的消息面板上
                client.appendMsg(text);
            }
            
        }       
    }
}

至此为止,程序已经进入到一个游戏桌中,并且添加了适当的 Listener,已经为玩游戏做好了准备,玩家退出游戏桌比较简单,只需要调用 currentPlace.leave() 方法,然后更新界面(比如 Disable “Leave” 按钮,Enable ”Enter”按钮)即可。

FGServer:

我们在“服务器端初始化”一节已经提到,FGServer 在初始化时会创建 3 个 FGServerTable 来表示游戏桌,每个 FGServerTable 对象都包含一个 Place 对象(注意,这里的 Place 属于 server 端,所在的包为 com.lotus.sametime.placessa, 而不是 client 端的 com.lotus.sametime.places)。Place 对象中添加的几个重要 Listener 如下:

步骤一:实现 PlaceListener


代码12:服务器端 PlaceListener

private class PlaceHandler extends PlaceAdapter
{
	public void sectionAdded(PlaceEvent event)
	{
	    Section section = event.getSection();	   
	    if (section.isStage())
	    {
            //如果新添加的section 是stage, 则添加一个listener, 实际上由于在创建Place时
//的设置,一个Place只可能有一个缺省的section: stage
	        stage = section;
	        stage.addSectionListener(new SectionHandler());
	
	    }
	}
	
	public void activityAdded(PlaceEvent event)
	{
	    activity = event.getActivity();	    
        //对Activity 添加Message Listener, 用来接收从客户端发送的消息
	    activity.addIncomingMessageListener(new IncomingMessageHandler());
	}
}

步骤二:实现 SectionListener

Section Listener 主要的功能是检测用户进入/离开 Section 的事件,从而维持游戏桌的状态:


代码 13:检测用户进入/离开 Section 的事件

private class SectionHandler extends SectionAdapter
{
        //有新玩家进入到section中
        public void usersEntered(SectionEvent event)
        {
            UserInPlace[] theUsers = event.getEnteredUsers();
            UserInPlace user = event.getEnteredUsers()[0];            
            
            //向已经在游戏桌中等待的其他玩家发送消息
            broadcast("User " + user.getName() + " entered table " + getName());
            // 把新玩家加入到列表中
            addToPlayerList(user);
            
            if (isFull())
            {
                // 如果游戏桌已经满了, 发送命令@game start 
                isGameStarted = true;
                broadcast(Constants.CMD_GAMESTART);
                broadcast("Game started - " + getPlayerNames());
            }
            else
            {
                broadcast("Waiting for other players in " + getName());
            }
        }
        // 玩家离开的游戏桌
        public void userLeft(SectionEvent event)
        {
            
            UserInPlace user = event.getDepartedUser();
            // 从游戏列表中把玩家删除
            removeFromPlayerList(user);
            isGameStarted = false;

            broadcast("User " + user.getName() + " left from table "
                    + getName());
            // 此时,游戏桌未满, 发送命令@game end
            isGameStarted = false;            
            broadcast(Constants.CMD_GAMEEND);
            // 告诉游戏桌中的现有玩家,需要等待
            broadcast("Waiting for other players in " + getName());
        }
}

步骤三:为 Activity 实现 IncomingMessage Listener


代码 14:处理从 server 端收到的命令

private class IncomingMessageHandler extends IncomingMessageAdapter
{
	public void textReceived(MessageEvent event)
	{	        
	    String text = event.getText();        
	    PlaceMember pm = event.getSender();
        // 安全起见,先查找该用户是否在游戏桌中
	    FGServerUser user = find(pm);
	    if (null == user)
	    {
	        Log.error("Can't find user " + pm);
	        return;
	    }
        // 执行FGClient 发出的命令
	    CmdBase cmd = CmdFactory.getInstance(text);
	    cmd.processCmd(fg, user, text);
	}
}

四、在游戏桌上同另一个玩家进行游戏

当两个玩家进入到同一个游戏桌后,FGServerTable 能通过 SectionListener 检测到游戏桌已满,这时候就会给两个玩家发送游戏开始的命令: @game start。FGClientTable 通过 MyMsgListener 收到以后,则会 Enable 游戏界面上的三个猜拳按钮:“Stone”,“Scissor”,“Paper”,玩家就可以出拳进行游戏了。图 5 展示了猜拳游戏的一个典型场景:

该图包含两个已经进入到游戏桌的用户:user1(位于 FGClient1 中),user2(位于 FGClient2 中),图中还展示了一个服务器 FGServer 用于处理客户端的请求。


图 5:FGClient 和 FGServer 交互图
图 5:FGClient 和 FGServer 交互图

步骤一:位于 FGClient 1 的玩家发出猜拳命令: guess stone

在该场景中,user1 首先发出猜拳命令,下面的代码会被调用(位于 FGClientTable 中):


代码 15:用户发出猜拳命令

public void guess(String input)
{
	//使猜拳按钮不可再次点击
client.setGuessEnable(false);
//通过Activity向服务器发送消息,根据点击按钮的不同,参数input的值可能是:
// (1) guess stone, (2) guess scissor (3)guess paper
	activity.sendText(input);
}

步骤二:FGServer 判断当前状态

FGServer 接收到客户端发送的命令以后,会进行一系列处理,最终 FGServerTable 的 checkStatus 方法会被调用。


代码 16:检查当前状态

public void checkStatus(FGServerUser currentPlayer)
{	if (isWaitingForJudge())
	{
        // 如果两个玩家都已经发出猜拳命令,则游戏判断胜负
	    RuleBase rule = RuleFactory.getInstance(Constants.RULE_NAME);
	    if (rule.judge(this, players))
	    {
            // 向两个玩家发送消息
	        this.sendGameResult(rule);
            //清除当前的猜拳结果,本轮游戏结束
	        this.clearGuessing();
            // 发送命令,下一轮游戏开始
	        broadcast(Constants.CMD_GAMESTART);
	    }
	}
	else
	{
        // 只有当前玩家发出猜拳命令,分别向两个用户发送消息, 参见上图的步骤2
// (黄色箭头)        
	    currentPlayer.sendText("Waiting for other player to guess...");
	    sendTextExceptUser(currentPlayer, currentPlayer.getName()
	            + " guessed.");
	}
}

步骤三. 位于 FGClient2 的玩家发出猜拳命令: guess paper

与步骤一相同,参见 代码 15

步骤四. FGServer 再次判断当前状态

此时两个玩家都已经猜拳,FGServer将判断胜负关系,发送消息给玩家(参见 图5 的绿色箭头)

调用的代码与步骤二相同,参见 代码16





回页首


总结

本文利用了 Server Toolkit 提供的 ServerAppService、PlacesAdminService 和 ActivityService 扩展了 Sametime Server 的功能,完成了一个简单的猜拳游戏。用户可以通过本文体验到 Server Toolkit 的开发方式和技巧,从而在此基础上进一步深入,利用这些 API 定制自己的应用,完成特定的需求。






回页首


下载

描述名字大小下载方法
示例代码 STServer,以及说明文件STServerSample.zip1063KHTTP
关于下载方法的信息


参考资料

学习

获得产品和技术

讨论


作者简介

刘欣是一位IBM CSDL的软件工程师,目前从事企业电子商务应用的开发。您可以通过 liuxinlx@cn.ibm.com 和他联系。


常红平是一位IBM CSDL的软件工程师,目前从事企业电子商务应用的开发。您可以通过 changhp@cn.ibm.com 和他联系。




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款