Portal和OpenSocial

    最近有个任务,就是要作一个像Igoogle同样能够拖拽的页面,而后开发一些小控件,能够动态维护和布局。以前没有接触过,感受可能就是些JS,外加两张表存储控件位置,以为应该还能实现,就试着作了下,由于以前据说过Portal这个名词,因而就本是遵循规范、借鉴开源、不重复造轮子的原则,在网上搜搜Portal相应规范和开源实现,开始了个人实现之路。在浪费了近一个月时间的仍但愿渺茫的时候,接触到了OpenSocial,才终于完成了任务。javascript


(一)Portalhtml

Portal一词中文翻译为门户,是基于Web的应用,一般提供个性化,单点登陆,整合不一样资源的综合信息展现平台。Portal展示在最终用户面前的是相似于Web网页的Portal页面。java

构成Portal页面的是可以创建和展示不一样内容的一系列Portlet。Portlet处理从Portal传递来的用户请求,动态生成输出内容的一个片断,展示在Portal页面的某个位置上。web

下图显示了Portal服务器、Portlet容器以及Portlet之间的关系。json

Portlet是一个符合JSR168标准的类,是运行于Portal上的真正表明业务逻辑的部件,负责展示内容、处理请求。在Portal搭建好后,主要的工做就是根据业务要求开发Portlet了。api

在部署Portlet到一个Portal时,除须要将逻辑代码拷贝过去外,还须要定义一个portlet.xml的配置文件来注册。Portal要支持Portlet须要是Portlet容器,就像tomcat是servlet容器同样,也就是说,须要扩展servlet容器才能够支持Portal功能。tomcat

咱们的实际状况是有多个项目,每一个项目都有单独的项目组维护,若是将每一个Portlet业务代码(java代码、js、jsp等)拷贝到Portal门面项目里,会形成逻辑混乱、维护困难,这确定是不能接收的。服务器

Portal的开源项目有Pluto、Jetspeed、Liferay。项目的功能依次递增,代码复杂度也依次递增。Pluto实现了JSR168规范,扩展servlet容器为Portlet容器,Jetspeed和Liferay都是在它的基础上构建的;Jetspeed实现了控件的动态增删除和简单的自定义;Liferay则是一个功能齐全的门户解决方案。app

我借鉴Liferay的源码来实现本身的Portal,但它的代码混乱、逻辑复杂,显示层struts一、servlet、volocity、FreeMarker 等各类技术滥用,后台代码组织更凌乱。并且代码使用复杂的ant组织方式,让人却步。因为Portlet固有的问题及Liferay实现方式的复杂,我最后放弃了使用这种技术。jsp

(二)OpenSocial

山穷水复疑无路,柳暗花明又一村。在绝望的时候我看到了OpenSocial。

OpenSocial是Google发布的一个项目,定位于为SNS平台定义一套通用API,让应用开发者只需使用OpenSocial API进行一次开发,就能够将应用发布在全部支持OpenSocial的平台中。OpenSocial定义了一系列协议、标准和接口,用于将应用、容器和其余客户端融合在一块儿。OpenSocial是基于Web的,开发人员可使用标准的javascript和html建立应用,应用可使用OpenSocial的接口,访问SNS平台提供的信息。

OpenSocial通常由如下几部分组成:

  • Gadget

指由第三方开发人员开发的应用,通常由xml配置文件、javascript和html等其余资源组成。经过javascript调用OpenSocial提供的标准通用API来和SNS平台进行交互。应用的开发者可使用OpenSocial的Javascript接口编写基于HTML和Ajax的Social应用,还可使用Flash/Flex技术,开发用户界面更友好的富Internet应用。Gadget运行于Gadget容器中。

  • Gadget容器:    

一个SNS平台,若是能够集成OpenSocial应用,咱们就称其为Gadget容器。做为一个Gadget容器,须要执行渲染Gadgets、代理请求、响应REST和RPC请求等工做,还须要实现OpenSocial标准中描述的接口,这些接口包括:获取用户信息、存储和读取用户活动、存储和读取数据、发送消息等。Apache Shindig是OpenSocial容器的一个参考实现。

  • 第三方网站

提供js及rest等风格的API,供开发的Gadget调用。这些Gadget通常会部署到第三方的平台,Gadget使用OpenSocial标准的Javascript接口作Ajax调用,经过SNS平台代理调用第三方网站的API。

如图:支持 OpenSocial 标准后的开发方式

控件简介

Gadget 是一个独立的应用。它由一个特定格式的 XML 文件定义,这个 XML 文件中包含定义 Gadget 应用行为的 HTML、CSS、JavaScript 代码和图片、声音、视频等资源。HTML 能够用来展示内容。JavaScript 用于获取服务器数据,执行应用逻辑,动态修改展示内容。CSS 用来指定内容展示的样式。下面的例子(helloworld.xml)展现了 Gadget 基本的元素。

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
    <ModulePrefs title="Hello World!">
        <Require feature="dynamic-height"/>
    </ModulePrefs>
    <Content type="html">
        <![CDATA[
           Hello, world!
         ]]>
    </Content>
</Module>

在这个例子中,开发人员能够看到定义 Gadget 行为的几个重要元素:

  • <Module> 表示这个 XML 文件定义了一个 Gadget。

  • <ModulePrefs> 描述 Gadget 的元数据和做者信息。

  • <Require feature=" dynamic-height " /> 声明了 Gadget 须要加载一个 Feature。Feature 实现了特定功能 JavaScript API。

  • <Content type="html"> 声明 Gadget 的内容是 HTML。

  • <![ CDATA[ … ]]> 包含了 Gadget 的内容:JavaScript、CSS、HTML。这个元素相似于 HTML 页面的 body 元素。

javaScript api

OpenSocial 中的 JavaScript API 经过 Feature 来组织。每一个 Feature 是一个能够单独加载的 JavaScript 模块。经过如下的语法,Gadget 能够声明加载某个 Feature。

<Require feature="dynamic-height"/>

Feature能够分为如下几类:

  • 展示一个 Gadget 确定都会用到的特性,诸如 globals、core、rpc。

globals 定义了一些全局变量,如 gadgets、shindig、osapi。

core 特性提供了展示一个 Gadget 所须要的核心功能,包括 io 操做、用户设置等。

rpc 特性提供了整个 rpc 调用的实现。shindig 默认使用 iframe 来展示 Gadget,若是 Gadget 须要访问外部容器定义的某些方法,就须要经过 rpc 调用来完成。

  • Gadget 容器用到的特性,诸如 shindig-container、container。

  • OpenSocial 相关的一些特性,诸如 osapi、opensocial-data、opensocial-reference 等。

  • 一些 util 特性,诸如 shindig.uri、shindig.xhrwrapper、xmlutil。

  • 跟 Gadget 的用户界面比较相关的特性,诸如 settitle、tabs、views、minimessages、flash。

settitle 顾名思义就是设置 Gadget 的标题,使用这个特性能够在 Gadget 里面根据须要来动态的设置 Gadget 的标题。

tabs 特性支持在 Gadget 里面方便的建立多个 tab 和对应的内容。

views 特性提供了能够在多个 view 之间切换的功能。Gadget能够定义多个 view,使用 views 特性能够自由的在多个 view 间切换。

minimessages 特性则提供了几种类型的提示消息,好比显示多长时间就自动消失的消息提示。

flash 特性则能够在 Gadget 里面嵌入 flash 文件。

  • 为了 Gadget之间的通讯所用到的特性,pubsub 和 pubsub-2。

经常使用的globals、core、rpc、util已经默认引入,其余的Feature须要显式require引入。

下面是一个复杂些的例子:

gadget.xml

<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <ModulePrefs title="Make Request Example">
    <Require feature="dynamic-height"></Require>
  </ModulePrefs>
  <Content type="html">
    <![CDATA[
      <script type="text/javascript" src="makeRequest.js"></script>
      <h4>Select an NHL team and press "GO!" to see more information</h4>
      <select id="team">
        <option value="BOS">Boston</option>
        <option value="PHI">Philadelphia</option>
        <option value="TBL">Tampa Bay</option>
        <option value="CHI">Chicago</option>
        <option value="VAN">Vancouver</option>
        <option value="SJS">San Jose</option>
      </select>
      <button type="button" onclick="lookupTeam()">GO!</button>
      <br />
      Team ID: <span id="teamID"></span><br />
      Team Name: <span id="name"></span><br />
      Conference: <span id="conference"></span><br />
      Division: <span id="division"></span>
      <script type="text/javascript">
        gadgets.util.registerOnLoadHandler(init);
      </script>
    ]]>
  </Content>
</Module>

makeRequest.js

function init(){
   var miniMessage = new gadgets.MiniMessage();
  miniMessage.createStaticMessage("Welcome to the OpenSocial Explorer!");
}

function lookupTeam() {
  var index = document.getElementById('team').selectedIndex;
  var options = document.getElementById('team').options;
  var teamID = options[index].value;
  var params = {};
  params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.JSON;
  var url = 'http://www.nicetimeonice.com/api/teams/' + teamID;
  gadgets.io.makeRequest(url, function(response) {
    if (response.errors.length == 0) {
      var data = response.data;
      document.getElementById('teamID').innerHTML = data.teamID;
      document.getElementById('name').innerHTML = data.name;
      document.getElementById('conference').innerHTML = data.conference;
      document.getElementById('division').innerHTML = data.division;
      gadgets.window.adjustHeight();
    } else {
      gadgets.error('There was an error making the request.');
    }
  }, params);
}

能够看到,OpenSocial并非为Portal打造的,它主要是为SNS平台的交互定义规范。但因为它的交互都是基于rest和标准的html,系统间的耦合很小,部署也更简单方便,是很好的一个选择。去掉它的社交属性,Gadget容器加上portal的管理方式,这不正是我想要的吗!

(三)OpenSocial版Portal

说真来容易,真作起来,仍是不易,好在前人已经铺路,我这个后来者就能够乘凉了。

infoScoop这个项目已经实现了我想要的全部功能!portal+OpenSocial,完美的组合。并且这个开源项目代码结构组织的很好,后台只负责返回json和js格式的数据,前台js负责处理Portlet(或叫Gadget)的展示逻辑、这样后台的代码量就不多,并且技术选型也很好,只用了hibernate和servlet,没有用什么怪异的技术,它使用Apache Shindig这个标准套件来解析Gadget,代码分层很清楚,很容易理解。

前台使用js处理展示逻辑时,使用js面向对象组织,代码可读性很强,组织的也很清楚。

终于在经历波折后实现了我想要的功能,感谢互联网的改变,让分布式系统交互更容易,感谢开源的力量。

相关文章
相关标签/搜索