WebObjects/Project WONDER/Frameworks/ERIMAdaptor
ERIMAdaptor 使用标准 WOComponents 为您的应用程序提供即时通讯界面。由于 AOL IM 等即时通讯界面固有的限制,此适配器的架构与普通的 HTTP 适配器有所不同。
- WOSessions 由好友名称跟踪。当好友联系服务器的即时通讯帐户时,将启动对话。对话将好友名称与 WOSession ID 关联起来。对话具有可配置的过期时间,但默认情况下在 5 分钟不活动后过期。WOSession 将具有与平时相同的过期时间,但好友名称与该会话之间的连接将消失,从而有效地使会话变得无用。
- 不同的即时通讯网络可能会对您的组件施加额外的限制。例如,大多数网络限制可以在一条消息中传输的字节数。目前框架不会自动拆分,但这是一个明显的改进,可能会在将来添加。
- WORequest 和 WOResponse 的某些功能可能无法与 HTTP 对应部分完全一样。例如,WORequest 中没有正常的 HTTP 标头。
- 好友名称和消息以表单值和请求用户信息字典的形式出现 - 使用哪种方法更方便。
- 如果您需要直接访问(强制过期等),则可以通过请求用户信息字典访问 Conversation 对象。
- 实现目前是所有对话的单线程。这将很快改变,我只是还没有时间测试它。
目前有使用 jaimbot 和 daim 库的 AIM 的 IInstantMessengerFactory 的实现。如果您有兴趣获取有关任一库的更多信息,jaimbot 可从http://jaimbot.sourceforge.net 获得,daim 可从http://daim.dev.java.net 获得。
ERIMAdaptor 是一个自定义适配器,因此可以使用 WO 上的 WOAdditionalAdaptors 选项添加它。
-WOAdditionalAdaptors ({WOAdaptor="er.imadaptor.InstantMessengerAdaptor";})
您的属性文件中还有一些新的设置可以(或必须)出现。
- IMFactory(可选,默认 er.imadaptor.AimBotInstantMessenger$Factory) - 用于创建即时通讯连接的工厂类。如果您想提供新的即时通讯网络类型,则应为此类提供的任何类实现 IInstantMessengerFactory 接口。
- IMScreenName(必需) - 服务器应登录的即时通讯帐户的屏幕名称
- IMPassword(必需) - 服务器应登录的即时通讯帐户的密码
- IMTimeout(可选,默认 5 分钟) - 对话超时时间(以毫秒为单位)
- IMAutoLogin(可选,默认“true”) - 适配器是否应自动登录 AIM。如果为 false,则必须调用 adaptor.connect()
- IMConversationActionName(可选,默认“imConversation”) - 启动对话时要调用的 DirectAction 的名称,默认情况下您必须在 DirectAction 类中创建一个公共 WOActionResults imConversationAction() { .. } 方法。
- IMWatcherEnabled(可选,默认“false”) - 是否希望第二个 AIM 帐户登录并监视第一个。大多数 AIM 库在一段时间后可能会出现无法启动的问题。如果您有两个 AIM 帐户,它们可以相互保持活动状态。
- IMWatcherFactory(可选,默认与 IMFactory 相同) - 如果 IMWatcherEnabled,则要使用的工厂类
- IMWatcherScreenName(可选,如果 IMWatcherEnabled 则必需) - 监视器即时通讯帐户的屏幕名称
- IMWatcherPassword(可选,如果 IMWatcherEnabled 则必需) - 监视器即时通讯帐户的密码
在您的代码中,可以使用以下请求标头。
- IsIM - Boolean.TRUE 如果当前请求是即时通讯请求(您也可以调用 InstantMessengerAdaptor.isIMRequest(WORequest))。
- IMConversation - 与此请求关联的对话
- BuddyName - 启动请求的好友的名称
- Message - 用户发送的消息
以下表单值在请求中可用。
- BuddyName - 启动请求的好友的名称
- Message - 用户发送的消息
要启动,您必须有一个与 IMConversationActionName 值匹配的直接操作方法(默认为“imConversation”)。此方法应返回即时通讯对话的第一个“页面”。
例如
public WOActionResults imConversationAction() { return pageWithName(SayHelloPage.class.getName()); }
对于每个请求,IM 适配器都需要知道后续请求到来时要调用哪个操作。在正常的 WOComponent 中,将其视为每个页面都有一个每次请求到来时都会被点击的“Next”按钮。您不是使用 WOSubmitButton 或 WOHyperlink,而是使用 IMAction 元素。此元素有一个属性 - “action”,它指向要在组件上调用的操作方法。由于即时通讯界面作为交互方法的固有局限性,每个页面只能触发一个 IMAction(具体来说,是页面上评估的最后一个 IMAction)。当您将用户的响应视为要执行的操作时,这是有道理的。WOForm 上没有“multipleSubmit”的语义等效项。
IMAction 是您可以使用的最简单的操作,尽管有几种常见的响应操作,并且 ERIMAdaptor 为它们提供了默认的操作实现。以下是一个使用 IMAction 的非常简单的对话示例(它只会一遍又一遍地说同样的话)。
您的 Java 组件看起来像这样
public class IMComponent extends WOComponent { public boolean userResponded; ...
public String buddyName() { return InstantMessengerAdaptor.buddyName(context().request()); } public WOActionResults processResponse() { userResponded = true; return null; } }
HTML 将是
<webobject name = "FirstContactConditional"> Hi <webobject name = "BuddyName"></webobject>! </webobject> <webobject name = "UserRespondedConditional"> Welcome back <webobject name = "BuddyName"></webobject>! </webobject> <webobject name = "IMAction"></webobject>
最后,WOD 文件将包含
FirstContactConditional : WOConditional { condition = userResponded; negate = true; } UserRespondedConditional : WOConditional { condition = userResponded; } BuddyName : WOString { value = buddyName; } IMAction : IMAction { action = processResponse; }
以下是一个示例对话记录可能的样子
Mike> Hey server! Server> Hi Mike! Mike> How's it going? Server> Welcome back Mike! Mike> Uh. OK. Server> Welcome back Mike! ...
IMConfirmation 只有一个绑定“confirmed”。如果来自即时通讯好友的响应与一组常见的“yes”、“no”等词语中的任何一个匹配,则 confirmed 将设置为适当的值。如果未找到 yes 和 no 词语,则 confirmed 将设置为 null。您应该将其绑定到 Boolean 而不是 boolean,以便您可以正确检测第三种状态并重新提出问题。请注意,这不是国际化的,因此目前它具有“yes”、“y”、“yep”、“true”、“no”、“n”、“nope”、“nah”作为已知值。
- confirmed = 三态 Boolean,当 Boolean.TRUE 时,响应为肯定,当 Boolean.FALSE 时,响应为否定,当为 null 时,响应与已知的真/假值都不匹配。
- action = 接收响应时要执行的操作方法
AreYouSureAction : IMConfirmationAction { confirmed = yesOrNo; action = nextStep; }
在上面的示例中,绑定“yesOrNo”是一个 Boolean,它将包含用户响应是否为确认。处理响应后,将调用“nextStep”操作,以便您可以评估“yesOrNo”值并相应地做出响应。
IMSearchMessageAction 允许您将 AIM 消息响应中出现的子字符串映射到其他对象。例如,您可以传递一个选项字典,将单词“hi”映射到对象 Greeting,或将单词“bug”映射到对象 BugReport。如果 AIM 响应中出现单词“hi”,它将返回匹配的对象作为其值。
- value = 用于写入第一个匹配值的绑定
- values = (必须指定“value”或“values”中的至少一个,但您也可以同时使用两者)用于写入所有匹配值的数组的绑定
- optionsDictionary = 响应中要查找的子字符串与这些子字符串关联的任意对象的映射
- optionsArray = 要查找的已知子字符串的列表
- optionKeyPath = (仅适用于 optionsArray)不是在 optionsArray 中查找值,而是在 optionsArray 中每个值的此键路径的值中查找;例如,optionsArray 可能包含 Person 对象,optionKeyPath 可能为“firstName”,因此这将匹配人员列表中的第一个名字。
- quicksilver = 类似 Quicksilver 的匹配方式(“NPE”匹配“NullPointerException”)
- action = 接收响应时要执行的操作方法
PickRequestTypeAction : IMSearchMessageAction { value = selectedOption; optionsDictionary = options; action = nextStep; }
在上面的示例中,“optionsDictionary”包含一个映射,其中键是响应中要查找的子字符串,而值是与它们关联的对象。例如,来自我们的错误跟踪系统的字典看起来像 {“bug”=>BugReportType 对象,“request”=>ServiceRequestType 对象}。“action”是在用户响应返回时要触发的 method,而“value”将包含与用户响应匹配的值。
当用户响应时,响应将由提供的 action 解释,“selectedOption”字段将包含与用户响应匹配的任何对象,或者如果没有匹配,则为 null,“nextStep” action method 将被调用。“nextStep”是一个正常的 action method,与任何其他 method 相同,只是它可以访问 Request 部分中描述的额外的 AIM 仅请求参数。
IMSearchOptionsAction,IMSearchMessageAction 的邪恶孪生兄弟,允许您搜索您的选项以查找收到的 AIM 响应(而不是 SearchMessage 搜索 AIM 响应以查找您的选项——反过来)。例如,您可以传递一个选项字典,将单词“Company XYZ”映射到对象 CompanyXYZ,或将单词“Company ABC”映射到对象 CompanyABC。如果 AIM 了单词“XYZ”,它将返回匹配的 CompanyXYZ 对象作为其值。
- value = 用于写入第一个匹配值的绑定
- values = (必须指定“value”或“values”中的至少一个,但您也可以同时使用两者)用于写入所有匹配值的数组的绑定
- optionsDictionary = 响应中要查找的子字符串与这些子字符串关联的任意对象的映射
- optionsArray = 要查找的已知子字符串的列表
- optionKeyPath = (仅适用于 optionsArray)不是在 optionsArray 中查找值,而是在 optionsArray 中每个值的此键路径的值中查找;例如,optionsArray 可能包含 Person 对象,optionKeyPath 可能为“firstName”,因此这将匹配人员列表中的第一个名字。
- quicksilver = 类似 Quicksilver 的匹配方式(“NPE”匹配“NullPointerException”)
- action = 接收响应时要执行的操作方法
PickCompanyAction : IMSearchOptionsAction { optionsArray = companies; optionKeyPath = "name"; value = company; values = companies; quicksilver = true; action = nextStep; }
上面的来自我们的错误报告系统的示例允许用户选择一个公司与错误关联。“optionsArray”包含一个 Company 对象的数组。“optionKeyPath”指定响应应该与 Companies 的“name”键路径的值进行比较。第一个匹配的结果 Company 对象将存储在“company”绑定中(如“value”所定义),如果有多个匹配,它们都将出现在“companies”列表中。Quicksilver 匹配在上面启用,响应处理完并设置绑定后,“nextStep” action 将被调用。
一个非常常见的用例是您想要向用户呈现一个选项列表,并让用户从该列表中选择。IMPickList 为此行为提供了一个方便的实现。而之前的 action 是“无头”的,IMPickList 实际上完全自行呈现列表。一个典型的用例是继续呈现 IMPickList,直到用户的选择缩减到一个为止。
一个示例对话可能看起来像
Server> Pick a company: Server> 1) Company XYZ Server> 2) Company VWX Server> 3) Company ABC User> X // note this matches #1 and #2 Server> Pick a company: Server> 1) Company XYZ Server> 2) Company VWX User> V // Company VWX is now selected Server> ...
或者
Server> Pick a company: Server> 1) Company XYZ Server> 2) Company VWX Server> 3) Company ABC User> 1 // picking by number uniquely identifies Company XYZ
或者
Server> Pick a company: Server> 1) Company XYZ Server> 2) Company VWX Server> 3) Company ABC User> XYZ // XYZ uniquely matches Company XYZ
- displayStringKeyPath = 用于显示列表中每个对象的字符串的键路径。该值应放在“引号”中。
- list = 要从中选择的选项列表的 NSArray
- quicksilver = 是否对用户响应使用 Quicksilver 风格的匹配(“NPE”匹配“NullPointerException”)
- selections = 匹配的选择列表
- selection = 单个匹配的选择(如果只有一个)
- action = 接收响应时要执行的操作方法
PickProductAction : IMPickListAction { list = [email protected]; selection = product; selections = products; displayStringKeyPath = "name"; quicksilver = true; action = nextStep; }
上面的示例让用户从 Products 列表(来自“list”绑定)中选择。“displayStringKeyPath”绑定指定 Product 的“name”键路径应该在列表中显示。当用户唯一标识单个 Product 时,Product 对象将绑定到“product”变量。如果有多个匹配,匹配的 NSArray 将绑定到“products”变量。Quicksilver 匹配已启用。响应处理完后,“nextStep” method 将被调用。请注意,在此示例中,“products”数组既是“list”绑定,也是“selections”绑定。当页面首次加载时,“products”NSArray 初始化了所有产品。nextStep method 继续返回同一个页面,直到只有一个产品被选中。在此之前,列表将使用与用户部分响应匹配的产品进行重置(如上面 IMPickList 的示例记录中)。
IMTextAction 是最简单的 IMAction 实现之一。它将用户的响应存储在 String 绑定中,并调用 action method。
- value = 用于存储用户响应的变量
- allowBlanks = 如果为 false,空字符串(response.trim.length == 0)将变为 null
- action = 接收响应时要执行的操作方法
AskNameAction : IMPickListAction { value = userName; allowBlanks = false; action = nextStep; }
上面的示例将用户的响应存储在“userName”变量中,并且不允许空白值(即它们变为 null)。当响应处理完后,“nextStep” action method 将被调用。