给Sametime添加离线消息的支持

shulgi 贡献于2012-01-14

作者 killor  创建于2007-03-15 02:34:00   修改者Casper  修改于2007-11-20 02:23:00字数16729

文档摘要:通过这个离线消息的客户端和服务端的学习大家可以更好的了解和使用 Sametime,并能够将自己的应用扩展到Sametime中去。 本文假定读者有一定的eclipse/Java开发经验,对Sametime有一定了解,将扩展Sametime的功能
关键词:

给Sametime添加离线消息的支持 上部分:客户端插件的实现 目标: 通过这个离线消息的客户端和服务端的学习大家可以更好的了解和使用 Sametime,并能够将自己的应用扩展到Sametime中去。 本文假定读者有一定的eclipse/Java开发经验,对Sametime有一定了解,将扩展Sametime的功能 正文: IBM Lotus Sametime Connect V7.5 基于 Eclipse 平台。所以您可以添加您开发的 Eclipse 插件作为Sametime的新功能。在本文中,将展示如何构建用于扩展 Lotus Sametime 客户机用户界面的 Eclipse 插件。本文向您展示的并不是一个简单的 hello world 插件,而是一个名为 Offline Message 插件的 Sametime 插件。这个插件可以向不在线的用户发送离线消息。关于服务器端针对离线消息的处理我们会在另一篇文章里介绍。在阅读本文之后,您可以很好地掌握创建自己的 Eclipse 插件来扩展 Lotus Sametime 7.5 客户机的方式。 离线消息的介绍: IBM Lotus Sametime 一直是领先的企业即时消息 (IM) 解决方案。在最新发布的7.5版本里有很多新技术和新特性,可以更好的满足企业的需求。具体请参考developerworks上的文章“了解 IBM Lotus Sametime 7.5 中的新特性和新技术”。大多数企业选择即时消息产品时,除了关心在线消息的功能外,还会关心是否能进行离线消息处理。所谓离线消息就是在线用户发给不在线用户的信息,现在大多数个人用的通讯产品里都有这个功能。Sametime并没有直接把离线消息处理的功能包含在现有的产品里去,但是它提供了相关扩展接口, 参考developerworks上的文章“扩展 IBM Lotus Sametime Connect V7.5” 通过这些扩展接口我们可以很容易的扩展Sametime现有的功能。我们的就是用这些接口来实现Sametime对离线消息的处理。 系统结构图: 图1. 系统结构图 Sametime Server Offline Server Sametime Client Sametime Client Offline Plugin 操作处理流程: 1. 在线用户user1选中离线用户user2 2. user1打开离线消息输入框输入给user2的离线消息 3. 离线消息服务监听到user1客户端发来的离线消息 4. 处理离线消息:保存内容,发送者,接收者到离线消息处理列表 5. user2启动客户端登陆Sametime 6. 离线消息服务监听到user2的上线消息 7. 查询离线消息处理列表,把发送给user2的离线消息转发送给user2 8. 删除离线消息处理列表user2的相关内容 客户端程序 Offline Message 插件预览 在开始构建 Offline Message 插件的旅程之前,最好先预览一下插件的外观如何。 图2. 客户端右健菜单 图3. 离线消息输入框 获得并准备开发环境 我们假设您已经安装了 Eclipse 3.2 IDE。若尚未安装,可以访问 Eclipse 网站 获取该应用程序。我们使用 Eclipse IDE 开发 Offline Message 插件。 启动 Eclipse IDE 并将目标平台改成 Lotus Sametime V7.5。把目标平台从 Eclipse 平台改成 Sametime 平台使您可扩展 Sametime 平台而不是扩展 Eclipse 平台。 把目标平台改成 Lotus Sametime V7.5 的操作步骤如下: 1. 在 Eclipse 中,选择 Window - Preferences。 2. 在 Preferences 对话框的左窗格中展开 Plug-in Development 项,随后选中 Target Platform。 3. 右窗格中将出现 Target Platform Preference Page。单击 Browse 更改位置。 4. 将您的目标平台更改为系统中包含 Lotus Sametime V7.5 插件目录的目录位置。例如,如果您把 Lotus Sametime V7.5 安装在默认位置,目标平台位置应为 C:\Program Files\IBM\Sametime Connect 7.5。 5. 单击 Reload。即可看到 Sametime 插件 图 4. 选择 Target Platform Preference 6. 单击Ok,完成配置。 关于eclipse开发环境的配置与插件的开发您可以参考developerworks上的文章“Eclipse简介和插件开发”和“开发 Eclipse 插件”。 为 Offline Message 插件创建插件项目 为了使用离线消息传递功能扩展 Sametime GUI,您需要创建一个插件。而要创建 Offline Message 插件,您需要一个在开发过程中容纳插件的插件项目。在 Eclipse 中创建插件项目的操作步骤如下: 1. 选择 File - New - Project。 2. 在 New Plug-in Project 向导中,选择 Plug-in Development - Plug-in Project。然后单击 Next。 3. 键入com.devworks.example.offlinemessage 作为项目名,然后单击 Next。 4. 键入Offline Message 作为插件名。键入 DeveloperWorks 作为插件提供者。 图 5. 新建插件项目 5. 请注意,应该选中选项 “This plug-in will make contributions to the UI”。Sametime API 提供了一种扩展 Sametime UI 的途径。如果您仅扩展 Sametime UI,那么将其插入 Eclipse UI 并不是必要的。 6. 接受其余默认值,并单击 Finish。 图 6. 插件项目结构 添加插件所需的Sametime Server API jar 包 更具体地说,我们的插件用到了Sametime提供的Server端API.所以我们要向插件项目中导入Commserver 的JAR 文件. 1. 在插件项目下新建lib目录并添加CommRes.jar,stcommsrvrtk.jar到lib目录,这两个jar包可以在\st75sdk\server\commserver\bin中找到。 图 7. 插件项目结构 2. 您需要向您的绑定的构建路径中添加CommRes.jar 和stcommsrvrtk.jar。右击com.devworks.example.offlinemessage 插件,在上下文菜单中选择 Properties。此时将显示插件的属性。在左窗格中选择 Java Build Path。在右窗格中选择 Libraries 选项卡。单击 Add JARs 按钮。添加 aCommRes.jar 和stcommsrvrtk.jar 图 8. Java Build Path 编辑插件的清单文件 更具体地说,将修改清单文件来指定额外的插件,Offline Message 插件需要使用这些插件来扩展 Lotus Sametime 客户机的用户界面。 1. 双击 META-INF/MANIFEST.MF 文件。打开 Plug-in Manifest Editor。如果 Plug-in Manifest Editor 没有出现,则双击 MANIFEST.MF 并选择 Open With - Plug-In Manifest Editor。 2. 在Plug-In Manifest Editor 中选择 Dependencies 选项卡。然后单击 Add 按钮。 图 8. Plug-In Manifest Editor Plug-In Manifest Editor 是 build.xml、plugin.xml 和 MANIFEST.MF 的 GUI 表示形式。在单击 Add 按钮之后,将出现一个带有可用插件列表的对话框。将 清单1. 依赖的插件 com.ibm.collaboration.realtime.people, com.ibm.collaboration.realtime.imhub, com.ibm.collaboration.realtime.core, com.ibm.collaboration.realtime.rtc.core, com.ibm.rcp.realtime.livenames, com.ibm.collaboration.realtime.community, com.ibm.collaboration.realtime.community.sametime, com.ibm.collaboration.realtime.rtc.protocols.sametime 插件都添加到您所需要的插件列表中。 如果对话框中没有出现任何一种插件,则需要验证目标平台是否正确。在完成上述操作之后,请保存并关闭 Plug-in Manifest Editor。 图 9. Plug-In Manifest Editor 添加具体客户端实现代码 我们定义了一个叫做com.devworks.example.offlinemessage.MSGSendDialog的类来实现消息的输入窗口,一个叫做com.devworks.example.offlinemessage.MSGSend的类来实现消息的发送,一个叫做com.devworks.example.offlinemessage. OfflineMessageDelegate的类来实现菜单的关联。 初始化客户机到Offline Server的通道服务 在启动 Lotus Sametime 客户机时,OfflineMessage 插件将尝试建立一个可以创建一个通道到 Offline Server服务器的通道服务。此通道服务用于用户的整个 Sametime 会话。更具体地说,将触发 Activator 类的 start 方法,而该方法又调用了 Activator 类的initializechannelService方法。 注意:每个插件都有一个 Activator 实例。因此,我们会将到Offline Server的连接缓存为 Activator 实例的一部分,而不是每次使用Offline Message上下文菜单时都建立一个新的通道服务。 在下面的代码中,将获得com.lotus.sametime.community.ChannelService对象的一个句柄。 清单2. Activator.initializechannelService private void initializechannelService() { try { CommunityServiceInternal csi = (CommunityServiceInternal) ServiceHub .getService(CommunityServiceInternal.SERVICE_TYPE); Community dc = csi.getDefaultCommunity(); rtcs = dc.getRtcSession(); Field fsession = rtcs.getClass().getDeclaredField("_session"); fsession.setAccessible(true); m_session = (STSession) fsession.get(rtcs); m_channelService = (ChannelService) m_session .getCompApi(ChannelService.COMP_NAME); } catch (SecurityException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (NoSuchFieldException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ServiceException e) { // TODO Auto-generated catch block e.printStackTrace(); } } 发送离线消息到Offline Server的方法 注意这里的SERVICE_TYPE要与Offline Server的SERVICE_TYPE保持一致 清单3. MSGSend.sendOfflineMessage private void sendOfflineMessage() { STId stid = new STId(person.getContactId(), ""); STUser user = new STUser(stid, person.getDisplayName(), ""); NdrOutputStream outStream = new NdrOutputStream(); try { user.getId().dump(outStream); outStream.writeUTF(user.getName()); outStream.writeUTF(msg); } catch (IOException e) { e.printStackTrace(); return; } Channel channel = m_channelService.createChannel(SERVICE_TYPE, 0, 0, EncLevel.ENC_LEVEL_ALL, outStream.toByteArray(), null); channel.open(); } 输入离线消息的对话框 用户在这里输入离线消息,点击ok的时候发送消息并关闭窗口,点击cancel的时候直接关闭窗口 清单4. MSGSendDialog public class MSGSendDialog implements SelectionListener { private Shell shell = new Shell(); private Button button1; private Button button2; private Text text; private Person person; public MSGSendDialog(Person person) { this.person = person; shell.setText("Offline Message"); createSShell(); shell.setSize(300, 200); shell.open(); } private void createSShell() { Label label = new Label(shell, SWT.WRAP); label.setText("Please input the messgae you want to send."); text = new Text(shell, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); button1 = new Button(shell, SWT.PUSH); button1.setText("OK"); button1.addSelectionListener(this); button2 = new Button(shell, SWT.PUSH); button2.setText("Cancel"); button2.addSelectionListener(this); final int insetX = 4, insetY = 4; FormLayout formLayout = new FormLayout(); formLayout.marginWidth = insetX; formLayout.marginHeight = insetY; shell.setLayout(formLayout); Point size = label.computeSize(SWT.DEFAULT, SWT.DEFAULT); final FormData labelData = new FormData(size.x, SWT.DEFAULT); labelData.left = new FormAttachment(0, 0); labelData.right = new FormAttachment(100, 0); label.setLayoutData(labelData); shell.addListener(SWT.Resize, new Listener() { public void handleEvent(Event e) { Rectangle rect = shell.getClientArea(); labelData.width = rect.width - insetX * 2; shell.layout(); } }); FormData button2Data = new FormData(); button2Data.right = new FormAttachment(100, -insetX); button2Data.bottom = new FormAttachment(100, 0); button2.setLayoutData(button2Data); FormData button1Data = new FormData(); button1Data.right = new FormAttachment(button2, -insetX); button1Data.bottom = new FormAttachment(100, 0); button1.setLayoutData(button1Data); FormData textData = new FormData(); textData.left = new FormAttachment(0, 0); textData.right = new FormAttachment(100, 0); textData.top = new FormAttachment(label, insetY); textData.bottom = new FormAttachment(button2, -insetY); text.setLayoutData(textData); } public void widgetDefaultSelected(SelectionEvent arg0) { } public void widgetSelected(SelectionEvent Event) { if (Event.getSource() == button1) { MSGSend ssd = new MSGSend(person, text.getText()); ssd.send(); } shell.dispose(); shell.close(); } } org.eclipse.ui.popupMenus 扩展点 要在右击 Sametime 合作伙伴时出现的上下文菜单中添加菜单项,需要创建扩展 LiveNameActionDelegate 类的类。还必须在 plugin.xml 文件中添加条目。关于该主题的更多信息,我们建议您阅读 developerWorks Lotus 文章 “利用 LDAP 目录查看插件扩展 Lotus Sametime 客户机” 深入了解这个概念。 com.devworks.example.offlinemessage.OfflineMessageDelegate类负责显示 GUI,允许您关联一个Sametime 合作伙伴。当调用OfflineMessage上下文菜单项时,触发 run 方法,而该方法又调用new MSGSendDialog(person)方法,向用户显示为选定的 Sametime 合作伙伴输入离线消息的界面 清单5. OfflineMessageDelegate package com.devworks.example.offlinemessage; import org.eclipse.jface.action.IAction; import com.ibm.collaboration.realtime.livenames.LiveNameActionDelegate; import com.ibm.collaboration.realtime.people.Person; public class OfflineMessageDelegate extends LiveNameActionDelegate { public void run(IAction arg0) { Person persons[] = getSelectedPersons(); Person person = persons[0]; if (person != null) { new MSGSendDialog(person); } } } 要在右击 Sametime 合作伙伴时出现的上下文菜单中添加OfflineMessage 菜单项,需要在 plugin.xml 文件中添加如下代码。注意扩展点的定义是如何指向OfflineMessageDelegate类的。 清单6. popupMenus extension point 在 Eclipse 中测试 Sametime 插件 从 Eclipse 的 Run 菜单中选择 Run。在 Run 对话框的左窗格中,右击 Eclipse Application 并选择 New_configuration。您就可以配置您的应用程序了。 图 10. Run Config Lotus Sametime 客户机应该表现为就像在 Eclipse 以外的地方运行一样。 图 11.Login dialog 到此针对客户机的扩展已经完成,接下来我们将在下部分介绍实现处理离线消息的服务器端程序Offline Server。 下部分:服务端处理离线消息的实现 目标: 通过这个离线消息的客户端和服务端的学习大家可以更好的了解和使用 Sametime,并能够将自己的应用扩展到Sametime中去。 本文假定读者有一定的eclipse/Java开发经验,对Sametime有一定了解,将扩展Sametime的功能 正文: 通过上部分文章的学习,我们知道Sametime客户端有很好的扩展性,其实Sametime 服务器端同样有良好的扩展性。通过IBM Lotus Sametime Software Development Kit(SDK)我们可以很容易的添加新的服务到Sametime Server中。本文向您展示的就是如何添加离线消息处理服务到Sametime Server里。在阅读本文之后,您可以很好地掌握创建自己的服务程序来扩展 Lotus Sametime 服务器的方式。关于离线消息的介绍,系统结构和处理流程请参考上部分内容,我们这里直接介绍服务器端程序的实现。 服务端程序 Sametime Java工具包包括访问Sametime服务器提供的各项服务的组件。在我们的Offline Server实例中用到的服务组件主要包括: · 服务器服务,使应用程序作为服务登录和退出Sametime和运行功能 · 通道服务,接受来自客户机的通道请求 · 即时事件服务,得到用户的上线通知 · 简单登陆服务,模拟发送方用户登陆Sametime · 令牌服务,等到发送方用户的登陆令牌 · 即时消息,用于发送信息到指定用户 您可以通过多种方式将需要的组件装载到应用程序中。最简便的方式是使用STSession 的loadAllComponents或loadSemanticComponents方法。您可以使用loadComponents 方法并传送您希望接入的组件列表来逐个装载组件。在您装载完应用程序组件之后,您需要获得它们各自API的引用信息以使用它们的功能。您可以使用STSession.getCompAPI()方法来做到这一点。 下面我们来看Offline Server服务器端的具体实现。 为 Offline Server创建Java项目 为了实现Offline Message Server,您需要创建一个Java项目。在 Eclipse 中创建Java项目的操作步骤如下: 1. 选择 File - New - Project。 2. 在 New Plug-in Project 向导中,选择 Java Project。然后单击 Next。 3. 键入com.devworks.example.offlineserver 作为项目名,然后单击 Next。 4. 然后点击Create new Source folder 创建一个新的source目录src后点击完成。 图 1. 插件项目结构 添加项目所需的Sametime Server API jar 包 更具体地说,我们的插件用到了Sametime提供的Server端API.所以我们要向插件项目中导入Commserver 的JAR 文件. 1. 在插件项目下新建lib目录并添加CommRes.jar,stcommsrvrtk.jar到lib目录,这两个jar包可以在\st75sdk\server\commserver\bin中找到。 图 2. 插件项目结构 2. 您需要向您的绑定的构建路径中添加CommRes.jar 和stcommsrvrtk.jar。右击com.devworks.example.offlinemessage 插件,在上下文菜单中选择 Properties。此时将显示插件的属性。在左窗格中选择 Java Build Path。在右窗格中选择 Libraries 选项卡。单击 Add JARs 按钮。添加 aCommRes.jar 和stcommsrvrtk.jar 图 3. Java Build Path 添加具体服务器端实现代码 我们定义了一个叫做com.devworks.example.offlineserver.OfflineMessagesSA的类来实现接收客户端发来的离线消息,一个叫做com.devworks.example.offlineserver.UsersHandler的类来实现发送离线消息给刚上线的用户。 初始化服务程序 创建一个STSession用于登陆到Sametime服务器,初始化通道服务和即时事件服务给接下来的程序使用。 清单1. OfflineMessagesSA.OfflineMessagesSA public OfflineMessagesSA() { String hostName="9.181.91.172"; //Sametime Server hostname // Create and load the session of components. try { m_session = new STSession("OfflineMessages"); String [] compNames = { ServerAppService.COMP_NAME, CommunityEventsComp.COMP_NAME, SATokenComp.COMP_NAME }; m_session.loadComponents( compNames ); m_session.start(); } catch(DuplicateObjectException e) { e.printStackTrace(); exit(); } m_hostName = hostName; // Get a reference to the needed components. m_commEvents = (CommunityEventsService)m_session.getCompApi(CommunityEventsService.COMP_NAME); m_commEvents.addUserLoginListener(this); ChannelService channelService = (ChannelService)m_session.getCompApi(ChannelService.COMP_NAME); channelService.addChannelServiceListener(this); login(hostName); } 登陆到Sametime服务器 向Sametime服务器注册服务,登陆进服务器 清单2. OfflineMessagesSA.login void login(String hostName) { ServerAppService saService = (ServerAppService)m_session.getCompApi(ServerAppService.COMP_NAME); short loginType = STUserInstance.LT_SERVER_APP; int[] supportedServices = { SERVICE_TYPE }; // Server applications login directly to the server, and not through // the mux. So we can't use the default port. Connection[] connections = { new SocketConnection(1516, 17000), }; saService.setConnectivity(connections); saService.addLoginListener(this); saService.loginAsServerApp(hostName, loginType, "OfflineMessages", supportedServices); } 实现通道监听事件 监听来自客户端的离线消息,并把它存储在Hashtable里 清单3. OfflineMessagesSA.channelReceived public void channelReceived(ChannelEvent event) { // Get the incoming data. Channel cnl = event.getChannel(); try { NdrInputStream inStream = new NdrInputStream(cnl.getCreateData()); STId receiverId = new STId(inStream); String receiverName = inStream.readUTF(); String message = inStream.readUTF(); System.out.println("channelReceived receiverId:"+receiverId.toString()); System.out.println("channelReceived receiverName:"+receiverName); System.out.println("channelReceived message:"+message); STUserInstance sender = cnl.getRemoteInfo(); System.out.println("channelReceived sender:"+sender.toString()); STUser receiver = new STUser(receiverId, receiverName, ""); UsersHandler handler = new UsersHandler(m_session, m_hostName, cnl.getRemoteInfo(), receiver, message); m_watchedUsers.put(receiverId.getId(), handler); } catch (IOException e) { e.printStackTrace(); cnl.close(STError.ST_INVALID_DATA, null); return; } cnl.close(STError.ST_OK, null); } 实现用户登陆的监听 获得用户上线的事件,当用户有离线消息的时候激活发送程序 清单4. OfflineMessagesSA.userLoggedIn public void userLoggedIn (UserLoginEvent event) { // Check if we are interested in this user. STUser user = event.getUserInstance(); Object o = m_watchedUsers.remove(user.getId().getId()); if (o != null) { ((UsersHandler)o).receiverOnline(); } } 离线消息的存储结构 存储离线消息的相关信息,接收者,发送者,具体消息等 清单5. UsersHandler.UsersHandler public UsersHandler(STSession saSession, String serverName, STUser sender, STUser receiver, String message) { m_sender = sender; m_receiver = receiver; m_message = message; m_serverName = serverName; // We need the sender's token for login. m_tokenService = (SATokenService) saSession .getCompApi(SATokenService.COMP_NAME); m_tokenService.addTokenServiceListener(this); m_mainLogin = (ServerAppService) saSession .getCompApi(ServerAppService.COMP_NAME); } 发送离线消息的到接受者的方法 当用户有离线消息的时候激活的程序 清单6. UsersHandler.receiverOnline void receiverOnline() { // First, create a session for the user. try { Calendar ss = Calendar.getInstance(); System.out.println(ss.getTimeInMillis()); m_session = new STSession("OfflineMessageUser" + this); new STBase(m_session); new ImComp(m_session); m_session.start(); } catch (DuplicateObjectException e) { e.printStackTrace(); return; } m_loginService = (LightLoginService) m_session .getCompApi(LightLoginService.COMP_NAME); m_imService = (InstantMessagingService) m_session .getCompApi(InstantMessagingService.COMP_NAME); // Now, try to get his token. m_tokenService.generateToken(m_sender); } OfflineServer拿到发送者的登陆令牌,用这个令牌模拟成发送者登陆到Sametime Server 清单7. UsersHandler.tokenGenerated public void tokenGenerated(TokenEvent event) { try { Token token = event.getToken(); STUser user = event.getUser(); // Now, we login as the sender. m_loginService.setLoginType(STUserInstance.LT_LIGHT_CLIENT_USER); m_loginService.addLoginListener(this); Field mip = user.getClass().getDeclaredField("m_ip"); mip.setAccessible(true); java.net.Inet4Address cadd = (java.net.Inet4Address) mip.get(user); m_loginService.loginByToken(token.getLoginName(), token .getTokenString(), m_mainLogin, cadd); } catch (SecurityException e1) { e1.printStackTrace(); } catch (NoSuchFieldException e1) { e1.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } 当OfflineServer已发送者身份登陆到Sametime以后,把先前的消息发送给接收者 清单8. UsersHandler.loggedIn public void loggedIn(LoginEvent event) { System.out.println("SA: Handler LoggedIn"); // Finally we can send the message. Im im = m_imService.createIm(m_receiver, EncLevel.ENC_LEVEL_ALL, 1); System.out.println("send message to :" + m_receiver.toString()); im.addImListener(new ImHandler()); // Wait a while to let the receiver initialize. try { Thread.currentThread().sleep(5000); } catch (InterruptedException e) { } im.open(); } 发送完消息后立刻登出服务器 清单8. UsersHandler.imOpened public void imOpened(ImEvent event) { // Send the message and leave asap. try {Thread.currentThread().sleep(5000); } catch (InterruptedException e) { } System.out.println("send message:" + m_message); event.getIm().sendText(true, m_message); // wait for a while to let the client wake up. try {Thread.currentThread().sleep(8000); } catch (InterruptedException e) { } cleanUp(); } 测试 Offline Server 1.设置Sametime Server 让其准许扩展服务应用 把VPS_BYPASS_TRUSTED_IPS=1添加到sametime.ini的[debug]段下 2.在Eclipse里运行OfflineServer 从 Eclipse 的 Run 菜单中选择 Run。在 Run 对话框的左窗格中,右击 Java Application 并选择 New_configuration。您就可以配置您的应用程序了。 图 4. Run config OfflineServer服务端收到离线消息时的输出 图 5. Console Log OfflineServer服务端在用户上线时转发离线消息时的输出 图 6. Console Log 参考资料 · 阅读 developerWorks Lotus 文章“了解 IBM Lotus Sametime 7.5 中的新特性和新技术”。 · 阅读 developerWorks Lotus 文章“扩展 IBM Lotus Sametime Connect V7.5”。 · 阅读 developerWorks Lotus 文章“利用 LDAP 目录查看插件扩展 Lotus Sametime 客户机” · 阅读 developerWorks Lotus 文章“Eclipse简介和插件开发”。 · 阅读 developerWorks Lotus 文章“开发 Eclipse 插件”。 · IBM 红皮书Working with the Sametime Client Toolkits 。 作者 刘大力

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享文档获得金币 ] 2 人已下载

下载文档