设为首页 收藏本站
查看: 938|回复: 0

[经验分享] IBM Lotus Quickr REST 服务简介

[复制链接]

尚未签到

发表于 2017-5-25 11:48:36 | 显示全部楼层 |阅读模式
IBM Lotus Quickr 让用户能够轻松地共享业务内容。Lotus Quickr 的一个重要设计原则是在开放的接口上构建应用程序,这让客户和合作伙伴可以在任何地方和时间访问内容——这称为按需信息(information on demand)原则。本文主要关注 Lotus Quickr Representational State Transfer(REST)服务,包括概述和一个解释如何使用 REST 服务的简单示例。我们要介绍可以用 Quickr REST 服务执行的基本操作;后续的文章将解释更高级的操作。

前提条件

您应该很好地了解 Java 和 Web 2.0 编程,才能从本文得到最大的收获。为了使用示例代码,需要基本了解 Eclipse 框架和 Apache Abdera 客户机工具箱。关于 Apache Abdera 客户机工具箱,请参考 developerWorks 文章 “认识 Atom 发布协议,第 3 部分: Apache Abdera 项目简介”。

Quickr REST 服务的目标是让开发人员能够尽可能轻松地构建协作解决方案。这些服务是围绕开放标准和 Web 2.0 技术设计的,所以我们只需基本了解现有的 Web 技术(比如 HTTP 和 XML),就可以构建应用程序。尤其是,可以使用 REST 样式的 URL 操作内容。这些服务基于 Atom Syndication Format(在RFC 4287中描述过,用于从 Lotus Quickr 访问内容)和 Atom Publishing Protocol(APP,用于向 Lotus Quickr 发布内容)。

按照 APP 的原理,文档库被当作 APP 集合,文档作为 APP 资源。为每个集合和资源定义 URL,客户机可以对 APP 定义的这些 URL 调用适当的 HTTP 方法,比如 GET、POST、PUT 和 DELETE。另外,这些 URL 符合一种可预测的模式,所以客户机可以编写 URL,而不必要求服务器提供它们。关于这些服务的完整细节,请参考IBM Lotus Quickr Developer's Guide。

关于 Quickr Connector

假设您是 Acme Corporation 的应用程序开发人员,这家公司配置了 Lotus Quickr。Acme 的架构师和设计师使用 Lotus Quickr 在一个 Lotus Quickr 位置存储体系结构和设计文档。开发人员常常需要这些文档,所以如果能够在 Eclipse 开发平台(这也是在 Acme 广泛使用的系统)中轻松地访问这些文档,那么开发人员的工作效率会更高。因此,您决定编写一个 Quickr Connector,Quickr Connector 是现有应用程序或框架的扩展,它使我们能够在任何地方和时间访问内容。例如,用于 IBM Lotus Notes 的 Quickr Connector 可以将 Lotus Quickr 文档的链接嵌入在邮件中。

在这个示例中,Lotus Connector 实现为一个 Eclipse 视图插件,可以通过它访问文档库。这个插件称为 QuickrNavigator,它提供一个包含树控件的 Eclipse 视图。可以配置这个视图,让它显示来自 Lotus Quickr 服务器的文档库。树控件将库显示为顶级节点,库下面的每个文件夹是一个可展开的节点,文档是叶节点。这个插件的最初设计支持以下操作:

·将本地文件上载到库或库中的文件夹
·刷新文件夹或库,列出最新的内容
·将文档下载到本地文件系统
·通过双击在相关联的应用程序中查看文档
·删除文档
在这个示例中,使用开放源码的 Apache Abdera 客户机解析 Atom feed 并创建到服务器的 HTTP 请求。

获取库的列表

首先,必须获得库的列表,这样才能在导航树中建立顶级节点。按照 Atom 的术语,文档库表示为集合。Atom 定义一个服务文档,作为获取集合的机制。要获得这个服务文档,需要知道服务器名称以及连接服务器所用的用户 ID 和密码。使用的 URL 是一个内省 URL(introspection URL),并且因为文档中发布了 URL 格式,所以对于给定的服务器,您可以自己构建 URL。对于此处的服务器,URL 如下所示:

http://quickr.acme.com/dm/atom/introspection

对这个 URL 执行 GET 请求来获取库列表。响应包含一个 Atom 服务文档,其中包含一个 <workspace> 元素和每个库的 <collection> 元素(见清单 1)。


清单 1. Atom 服务文档


<service>
<workspace title="Teamspace Documents">
  <collection title="Architecture Documents" href="http://quickr.acme.com/library/
  5d06ab0044ed8129bd5ebd4caeec5df1/feed">
<accept>application/*,image/*,*/*</accept>
  </collection>
  <collection title="Design Documents" href="http://quickr.acme.com/library/
  3c06ab0044ed8129bd5ebd4cbeec5dc4/feed">
<accept>application/*,image/*,*/*</accept>
  </collection>
</workspace>
</service>



title 属性的值用作树节点的标签。当在树中展开节点时,使用 <collection> 元素的 href 属性中的 URL 获取库的内容。清单 2 给出处理这个响应的部分代码。


清单 2. 处理响应的部分代码


try {
httpClient.addCredentials(serverConfig.getUrl(), null, null,
new UsernamePasswordCredentials(serverConfig.getUserId(),
serverConfig.getPassword()));

httpClient.usePreemptiveAuthentication(true);

ClientResponse response = httpClient.get(serverConfig.getUrl()
+ "/dm/atom/introspection");

if (response.getStatus() == 200) {

Document serviceDoc = response.getDocument();
Element element = serviceDoc.getRoot().getFirstChild();
while (element != null) {
if (element instanceof Workspace) {
Workspace ws = (Workspace) element;
Iterator collections = ws.getCollections()
.iterator();
while (collections.hasNext()) {
TreeParent collection = new TreeParent(
(Collection) collections.next(),
true);
invisibleRoot.addChild(collection);
}
}
element = element.getNextSibling();
}
}
} catch (Exception e) {
e.printStackTrace();
showMessage(e.toString());
}



处理了 Atom 服务文档之后,插件就可以与用户进行交互了(见图 1)。


图 1. 插件显示从服务器获得的库列表



获得文件夹和文档的列表

既然已经建立了树的顶级节点,就该显示库中的文档和文件夹了。为此,需要检索库中的内容并建立子节点(文件夹和文档)。因为已经存储了每个库节点的 feed URL,所以很容易获取内容;只需对这个 URL 发出一个 GET 请求,以返回一个 Atom Feed 文档(见清单 3):

http://quickr.acme.com/dm/atom/library/5d06ab0044ed8129bd5ebd4caeec5df1/feed


清单 3. Atom Feed 文档


<?xml version="1.0" encoding="UTF-8"?>
<feed xml:base="http://quickr.acme.com/dm/atom/library/
5d06ab0044ed8129bd5ebd4caeec5df1/" xmlns="http://www.w3.org/2005/Atom">
  <generator uri="http://quickr.acme.com/dm/atom"
  version="1.0">Teamspace Documents</generator>
  <id>urn:lsid:ibm.com:td:5d06ab0044ed8129bd5ebd4caeec5df1</id>
  <link href="feed" rel="self"></link>
  <link href="http://quickr.acme.com/wps/mypoc?uri=
  dm:5d06ab0044ed8129bd5ebd4caeec5df1&verb=view" rel="alternate"></link>
  <link href="feed?pagesize=2&page=3" rel="next"></link>
  <link href="feed?pagesize=2&page=1" rel="previous"></link>
  <collection href="feed" xmlns="http://purl.org/atom/app#">
    <atom:title type="text" xmlns:atom="http://www.w3.org/2005/
    Atom">Architecture Documents</atom:title>
    <accept>application/*,image/*,*/*</accept>
  </collection>
  <author>
    <uri>uid=jsmith,o=acme</uri>
    <name>John Smith</name>
    <email>jsmith@acme.com</email>
  </author>
  <title type="text">Architecture Documents</title>
  <updated>2007-04-10T13:07:00.672Z</updated>

  <entry xml:lang="en">
    <id>urn:lsid:ibm.com:td:7f37550044f10d5b9144bbd6afe18010</id>
    <link href="document/7f37550044f10d5b9144bbd6afe18010/entry" rel="self"></link>
    <link href="http://quickr.acme.com/wps/mypoc?uri=
    dm:7f37550044f10d5b9144bbd6afe18010&verb=view" rel="alternate"></link>
    <link href="document/7f37550044f10d5b9144bbd6afe18010/entry" rel="edit"></link>
    <link href="document/7f37550044f10d5b9144bbd6afe18010/media"
    rel="edit-media"></link>
    <link href="document/7f37550044f10d5b9144bbd6afe18010/media"
    rel="enclosure" type="application/msword" title="Architecture Guidelines.doc"
    hreflang="en" length="19968"></link>
    <category term="document" scheme="tag:ibm.com,2006:td/type"
    label="document"></category>
    <author>
      <uri>uid=jsmith,o=acme</uri>
      <name>John Smith</name>
      <email>jsmith@acme.com</email>
    </author>
    <title type="text">Architecture Guidelines.doc</title>
    <published>2007-04-11T16:51:04.594Z</published>
    <updated>2007-04-11T16:51:04.594Z</updated>
    <td:created>2007-05-13T19:03:25.500Z</td:created>
    <td:modified>2007-05-13T19:03:25.500Z</td:modified>
    <td:modifier>
      <td:uri> uid=jdoe,o=acme </td:uri>
      <td:name>John Doe</td:name>
      <td:email>jdoe@acme.com </td:email>
    </td:modifier>
    <summary type="html"><span><img align="middle"
    src="thumbnail/7f37550044f10d5b9144bbd6afe18010/
    media></span><span>&nbsp;&nbsp;</span><span>
    General guidelines for architecture </span></summary>
    <content type="application/msword" xml:lang="en"
    src="document/7f37550044f10d5b9144bbd6afe18010/media"></content>
  </entry>

  <entry>
    <id>urn:lsid:ibm.com:td:5dc3f38044eee4ca90d8bad6afe18010</id>
    <link href="folder/5dc3f38044eee4ca90d8bad6afe18010/entry" rel="self"></link>
    <link href="http://quickr.acme.com/wps/mypoc?uri=
    dm:5dc3f38044eee4ca90d8bad6afe18010&verb=view" rel="alternate"></link>
    <link href="folder/5dc3f38044eee4ca90d8bad6afe18010/entry" rel="edit"></link>
    <category term="folder" scheme="tag:ibm.com,2006:td/type"
    label="folder"></category>
    <author>
      <uri>uid=jsmith,o=acme</uri>
      <name>John Smith</name>
      <email>jsmith@acme.com</email>
    </author>
    <title type="text">Johns Folder</title>
    <published>2007-04-10T23:58:29.219Z</published>
    <updated>2007-04-10T23:58:29.219Z</updated>
    <td:created>2007-05-13T19:03:25.500Z</td:created>
    <td:modified>2007-05-13T19:03:25.500Z</td:modified>
    <td:modifier>
      <td:uri> uid=jdoe,o=acme </td:uri>
      <td:name>John Doe</td:name>
      <td:email>jdoe@quickr.acme.com </td:email>
    </td:modifier>
    <summary type="text">John's architecture documents</summary>
    <content type="application/atom+xml"
    src="folder/5dc3f38044eee4ca90d8bad6afe18010/feed"></content>
  </entry>

</feed>



对于库根下面的每个文件夹和文档,这个 feed 包含一个 Atom Entry。<category> 元素指出这个条目对应于一个文件夹,还是对应于文档。在树中将文件夹显示为可展开的节点,因为它们可以包含子文件夹和文档。文档显示为叶节点。在 feed 文档中可以看到,每个条目都有一个链接到本身的URL,这是 Atom 中另一个有用的模式,也是链接元素的用途。链接提供了内容项目上相关的内容、视图或动作的 URL。这使应用程序不必处理编写这些 URL 的一些工作(尽管,正如前面提到的,这些 URL 是可预测的)。

对于文件夹条目,将 self 链接存储在 TreeParent 实例中,后面将用它来编写文件夹的 feed URL。就像使用库 feed URL 存储和检索库内容一样,可以使用文件夹的 feed URL 存储或检索文件夹的内容。

对于文档条目,需要获取文档的内容。因此,把文档条目的 edit-media 链接存储在它的 TreeObject 实例中。关于这些链接关系的说明,请参阅Atom Publishing Protocol 规范。清单 4 给出将 Atom Entry 处理为树节点的部分代码。


清单 4. 将 Atom Entry 处理为树节点的部分代码


ClientResponse response = httpClient.get(url);
if (response.getStatus() == 200) {
Feed feed = (Feed) response.getDocument().getRoot();
Iterator entries = feed.getEntries().iterator();
while (entries.hasNext()) {
boolean isFolder = false;
Entry entry = (Entry) entries.next();
try {
Iterator categories = entry.getCategories(
"tag:ibm.com,2006:td/type").iterator();
while (categories.hasNext()) {
Category cat = (Category) categories.next();
if (cat.getTerm().equals("folder")) {
isFolder = true;
break;
}
}
} catch (IRISyntaxException e) {
e.printStackTrace();
}
if (isFolder) {
TreeParent folder = new TreeParent(entry, false);
addChild(folder);
} else {
TreeObject document = new TreeObject(entry);
addChild(document);
}
}
}



在处理了库的 Atom Feed 文档之后,插件显示库的内容(见图 2)。


图 2. 插件显示库的内容



获取文档内容

文档的媒体内容是用户希望阅读或更新的数据。例如,媒体内容可以是 PDF 文件。在显示库中的文档列表之后,用户可以通过双击文档查看其媒体内容。当用户双击文档时,需要在相关联的应用程序中打开文档(比如用 Adobe Reader 打开 PDF 文件)。首先,需要获得文档的媒体内容,让应用程序有数据可处理。这需要使用保存在文档节点的 TreeObject 实例中的 edit-media 链接:


http://quickr.acme.com/dm/atom/library/5d06ab0044ed8129bd5ebd4caeec5df1
/document/7f37550044f10d5b9144bbd6afe18010/media



在对这个 URL 发出 GET 请求时,会在响应中返回文档的媒体内容。读取响应,将它保存在一个临时文件中,然后使用相关联的应用程序运行这个临时文件。清单 5 给出执行这个操作的代码。


清单 5. 下载和运行文档的部分代码


public void doOpen(String url) {
    TreeObject item = (TreeObject) ((IStructuredSelection) viewer
        .getSelection()).getFirstElement();
    try {
        String tmpDir = File.createTempFile("qkr",
            "tmp").getParent();
        File file = new File(tmpDir + "/" + item.getName());
        if (file.exists()) {
            file.delete();
        }
        ClientResponse response = httpClient.get(url);
        if (response.getStatus() == 200) {
                BufferedInputStream bis = new BufferedInputStream(
                    response.getInputStream());
                file.createNewFile();
                BufferedOutputStream bos = new BufferedOutputStream(
                    new FileOutputStream(file));
                byte[] bytes = new byte[1024];
                int count = 0;
                while ((count = bis.read(bytes)) != -1) {
                    bos.write(bytes, 0, count);
                }
                bis.close();
                bos.close();

                // open the local file in editor
                IWorkspace ws = ResourcesPlugin.getWorkspace();
                IProject project = ws.getRoot().getProject("Quickr Files");
                if (!project.exists()) {
                    project.create(null);
                }
                if (!project.isOpen()) {
                    project.open(null);
                }
                IPath location = new Path(file.getPath());
                IFile iFile =
                    project.getFile(location.lastSegment());
                if (!iFile.exists()) {
                    iFile.createLink(location, IResource.NONE, null);
                }
                FileEditorInput fileEditorInput = new FileEditorInput(iFile);
                IEditorRegistry registry = PlatformUI.getWorkbench()
    .getEditorRegistry();
                IWorkbenchPage page = getViewSite().getWorkbenchWindow()
                    .getActivePage();
                if (page != null) {
                    if( registry.isSystemExternalEditorAvailable(
                        iFile.getName()))
                    {
                        page.openEditor( fileEditorInput,
                            IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID);

                    } else if
                        (registry.isSystemInPlaceEditorAvailable(iFile
                        .getName())) {

                        page.openEditor(fileEditorInput,
                            IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID);
                    } else {
                        showMessage("No viewer available for this file type.
                            You can download it instead.");
                    }
                }
        }
        response.release();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (CoreException e) {
        e.printStackTrace();
    }
}


上载文件

现在假设您希望从库(或文件夹)的上下文菜单中选择 Upload,从而将本地文件存储在 Lotus Quickr 中。这需要使用树节点的 TreeParent 实例中存储的 feed URL:

http://quickr.acme.com/dm/atom/library/5d06ab0044ed8129bd5ebd4caeec5df1/feed

在前面,通过向这个 URL 发送 GET 请求来检索库的内容。现在,通过向这个 URL 发送 POST 请求来存储文档。这个请求是由 APP 规范定义的,它使用 POST 操作创建资源。在发送 POST 请求时,把文档的媒体内容写在请求内容中。但是,服务器如何知道把文件保存在库中的什么地方以及使用哪个文件名?

答案就是 Slug 头,可以通过 Slug 头向 Lotus Quickr 建议采用哪个名称作为文档的文件名。将 Slug 头的值设置为文档相对于库根的相对路径。例如,如果希望将文件 MyFile.doc 存储在库中的 MyFolder 文件夹中,那么应该将 Slug 头设置为 /MyFolder/MyFile.doc。清单 6 给出了在插件中执行这个操作的代码。


清单 6. 在文档库中存储本地文件的代码
public void doUpload(String url) {
    FileDialog dlg = new FileDialog(getViewSite().getShell(), SWT.OPEN);
    String path = dlg.open();
    if (path != null) {
        File file = new File(path);
        RequestOptions ptions = new RequestOptions();
        options.setSlug(file.getName());
        options.setContentType("unknown/unkown");
        options.setHeader("Content-Length", String.valueOf(file.length()));
        try {
            ClientResponse response = httpClient.post(url,
                new FileInputStream(file), options);
            if (response.getStatus() != 201) {
                showMessage(response.getStatusText());
            } else {
                ISelection selection = viewer.getSelection();
                TreeParent parent = (TreeParent) ((IStructuredSelection) selection)
                    .getFirstElement();
                parent.clear();
                viewer.refresh(parent);
            }
            response.release();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}


在成功地处理这个请求之后,服务在响应中返回状态码 201。响应还包含一个 Location 头,其中包含刚创建的文档内容的 URL(即 edit-media 链接)。可以使用这一信息更新树,以显示新的文档节点。为了简化,这个插件会刷新父节点来显示新添加的文档。最终,文件会添加到库中并显示在树中。

删除文档

现在,看看如何使用这个插件从库中删除文档。这需要使用库节点下面每个节点中存储的 self 链接。Quickr REST 服务不支持删除库本身,所以我们不在库节点上提供 Delete 菜单(见清单 7)。


清单 7. 删除文档的代码


public void doDelete(String url) {
String entryUrl = url;
if (url.endsWith("/media")) {
entryUrl = entryUrl.substring(0, url.lastIndexOf('/'));
entryUrl += "/entry";
}
TreeObject item = (TreeObject) ((IStructuredSelection) viewer
.getSelection()).getFirstElement();
TreeParent parent = item.getParent();
RequestOptions ptions = new RequestOptions();
options.setHeader("X-Method-Override", "DELETE");
ClientResponse response = httpClient.post(entryUrl,
new StringRequestEntity(""), options);
if (response.getStatus() == 200) {
parent.clear();
viewer.refresh(parent);
}
}



最后,简要介绍一下其他菜单。Refresh 操作的作用是获取库或文件夹的内容。Download 操作是 Doubleclick 操作的一部分,Doubleclick 操作会下载并运行文件。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-380950-1-1.html 上篇帖子: 【求职经历】-JobHuting At IBM 未完成 下篇帖子: How to apply a certificate from IBM after having passed some IBM's tests
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表