程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Eclipse環境下的OpenSocial開發

Eclipse環境下的OpenSocial開發

編輯:關於JAVA

通過Shindig SPI擴展創建自己的OpenSocial容器

隨著社交網絡的不斷發展,用戶關系信息已經成為一類重要的網絡數據。為了能使開發者在社交網絡 平台上開發出富體驗的應用,充分挖掘和共享平台的用戶關系數據,從而極大豐富 SNS 自身的功能,開 放平台(OpenAPI)已經成為各主流社交網站的共同趨勢。OpenSocial 為構建跨多個網站的社交應用程序 提供了一組通用 API。開發人員可以自由使用包括 JavaScript、HTML 在內的標准的 Web 技術創建應用 程序,用以訪問社交網絡的用戶關系信息。Shindig 是 OpenSocial 規范的引用實現,旨在幫助 OpenSocial 開發人員快速構建自己的 OpenSocial 應用平台。本文通過實際的例子,指導讀者如何在 Eclipse 環境下構建 / 編譯 / 調試 Apache 的 Shindig Java 工程,及其如何通過 SPI 實現,把現有 的用戶關系數據適配到 Shindig 容器。

什麼是 OpenSocial

OpenSocial 是基於開放標准的一組通用的 API,用於幫助 WEB 的開發者構建跨多個社交網站的可移 植的社交應用程序。OpenSocial 提供開發者一套通用的 API,基於該通用 API 開發的社交應用程序可以 運行在任意支持 OpenSocial 規范的社交網站上。

關於更多的有關 OpenSocial 內容,請讀者參見 www.opensocial.org.

Apache Shindig

Shindig 是 OpenSocial 規范的引用實現,其主要的組件包括 :

Gadget Container JavaScript,OpenSocial Gadget 容器,客戶端的 JavaScript 類庫 (gadget.js) ,提供例如 UI Layout,Security, Communication 等相關的功能。

Gadget Rendering Server,負責解析 Gadget XML, 轉化成浏覽器使用的 HTML/JavaScript/CSS。

OpenSocial Container JavaScript,位於客戶端的 OpenSocial 容器,也是 JavaScript 類庫,提供 OpenSocial 相關的功能,例如存取 People, Activity, AppData 等相關的社交數據。

OpenSocial Data Server,提供基於 Restful/RPC 協議的 Services,用於存取 People, Activity, AppData 等相關的社交數據

圖 1 是 Shindig 的服務器端架構圖:

圖 1. Shindig Architecture( 引自 Chris Schalk@GoogleTM)

從圖 1 中可以看到,Shindig 基於 Java Servlet Stack 實現。GadgetRenderingServlet 負責 Gadget Rendering, 而 DataServiceServlet 和 JsonRpcServlet 實現 OpenSocial Data Server 中相對 應的 Restful 及其 RPC 服務。JsonDbOpensocialService 通過實現 ActivityService, PersonService, AppDataService 三個接口向 Shindig OpenSocial 容器提供基於 Json 格式的 OpenSocial 數據。客戶 端的 Gadgets 可以使用標准的 OpenSocial API 訪問到這些數據。

關於更多的有關 Apache Shindig 內容,請讀者參見 http://incubator.apache.org/shindig.

Eclipse 環境下編譯 / 調試 Shindig

我們通過以下的步驟來完成:

安裝 Maven plugin

Maven 是一個基於 Java 的代碼構建和依賴管理工具,Apache Shindig 的源代碼是通過 Maven 來管 理的,所以我們需要安裝 Maven 的 Eclipse 插件,讀者可以使用 Eclipse 的 updatesite 機制,連接 到"http://m2eclipse.sonatype.org/update/"站點安裝。

使用 Subversion 下載 Shindig 代碼

在 http://svn.apache.org/repos/asf/incubator/shindig/trunk/,使用 SVN 客戶端下載到 Shindig 的源代碼。

編譯和調試 Shindig

首先,在 Eclipse IDE 裡,通過 File/Import/General/Maven Projects 選項導入我們下載的所有 Shindig 的源代碼。導入完成後,Shindig 就作為幾個 Maven 工程存在於你當前的 WorkSpace 中。

通過 Run/Debug Configurations/Maven Build 配置編譯 Shindig 參數,如圖 2 所示:

圖 2. Package Shindig

如圖 2 所示,“E:\svn_repository\opensocial-shindig”是你的 Shindig 源代碼的根目錄。點擊 Debug, 這將使用 Maven 來 Build 整個 Shindig 代碼。在 Build 成功後,我們使用 Jetty 來啟動 Shindig,默認情況下,Jetty Server 將運行在 8080 端口。如圖 3 所示:

圖 3. Run Shindig

如圖 3 所示, 我們設置了 Maven 目標,使用 Jetty 來啟動 Shindig, 而 Base directory 設置為 shindig-server Maven 工程的根目錄。點擊 Debug, Jetty Server 運行,而 Shindig 部署在 Jetty Server 上。 在 Shindig 成功啟動後, 你就可以使用 http://localhost:8080/gadgets/files/samplecontainer/samplecontainer.html來訪問 Shindig 提供 的 Gadget 的例子。

Shindig 服務器端 SPI 擴展

Shindig 作為 OpenSocial 規范的引用實現,提供了 SPI 的擴展能力,允許你把數據適配到 Shindig 容器中去。你的這些數據也許存在於諸如 My SQL/Oracle 的關系數據庫,或者是以 JSON 格式存儲的靜 態文件,無論哪種存儲,你都可能通過 Shindig SPI 將它們適配到 Shindig, 從而使這些數據公布在 OpenSocial 平台上。

圖 4. Shindig SPI 擴展

如圖 4 所示,你的應用需要實現 ActivityService, PersonService, AppDataService 三個接口,利 用諸如 JDBC/Hibernate 等機制把數據提供給 Shindig。

接下來,本文將通過一個例子,實現 PersonService 接口向 Shindig 提供 People/Friends 相關的 OpenSocial 數據。

清單 1 是 SocialTestJsonPersonService類的實現。

清單 1. SocialTestJsonPersonService Class

public class SocialTestJsonPersonService implements PersonService {
  private static final String PEOPLE_TABLE = "people";
  private static final String FRIEND_LINK_TABLE = "friendLinks";
  private JSONObject db;
  private BeanConverter converter;
     ……
  public Future<RestfulCollection<Person>> getPeople(Set<UserId>
        userIds,GroupId groupId, CollectionOptions options, Set<String>  fields,
    SecurityToken token) throws ProtocolException {
   List<Person> result = Lists.newArrayList();
   try {
    //Read people data from JSON table.
    JSONArray people = db.getJSONArray(PEOPLE_TABLE);
    Set<String> idSet = getIdSet(userIds, groupId, token);

    for (int i = 0; i < people.length(); i++) {
     JSONObject person = people.getJSONObject(i);
     if (!idSet.contains(person.get(Person.Field.ID.toString()))) {
      continue;
     }
     // Add group support later
     Person personObj = filterFields(person, fields, Person.class);
     result.add(personObj);
    }

    if (GroupId.Type.self == groupId.getType() && result.isEmpty()) {
     throw new ProtocolException(HttpServletResponse.SC_BAD_REQUEST,
       "Person not found");
    }
    int totalSize = result.size();
    return ImmediateFuture.newInstance(new RestfulCollection<Person>(
      result, options.getFirst(), totalSize, options.getMax()));
   } catch (JSONException je) {
    throw new ProtocolException(
      HttpServletResponse.SC_INTERNAL_SERVER_ERROR, je
        .getMessage(), je);
   }
  }

  public Future<Person> getPerson(UserId id, Set<String> fields,
    SecurityToken token) throws ProtocolException {
   try {
    //Read people data from JSON table.
    JSONArray people = db.getJSONArray(PEOPLE_TABLE);
    for (int i = 0; i < people.length(); i++) {
     JSONObject person = people.getJSONObject(i);
     if (id != null 
       && person.get(Person.Field.ID.toString()).equals(
         id.getUserId(token))) {
      Person personObj = filterFields(person, fields,
        Person.class);
      return ImmediateFuture.newInstance(personObj);
     }
    }
    throw new ProtocolException(HttpServletResponse.SC_BAD_REQUEST,
      "Person not found");
   } catch (JSONException je) {
    throw new ProtocolException(
      HttpServletResponse.SC_INTERNAL_SERVER_ERROR, je
        .getMessage(), je);
   }
  }
     ……
  }

從清單 1 可以看到,SocialTestJsonPersonService 實現了 PersonService 兩個接口方法 getPeople 及其 getPerson。getPeople 根據傳入參數 userIds,返回相應於該 ID 列表的用戶列表,而 getPerson 根據傳入參數 id,返回相應於該 ID 的用戶。

注意,Shindig 依賴 Guice 做動態的依賴注入 (dependency Injection),我們需要在 org.apache.shindig.social.sample.SampleModule 裡指示 Guice 把 PersonService 綁定到 SocialTestJsonPersonService 實現,如清單 2 所示:

清單 2. SampleModule Class

public class SampleModule extends SocialApiGuiceModule {

  @Override
  protected void configure() {
   super.configure();

   bind(String.class).annotatedWith(Names.named("shindig.canonical.json.db"))
     .toInstance("sampledata/canonicaldb.json");

   bind(String.class).annotatedWith(Names.named("shindig.socialtest.json.db"))
   .toInstance("sampledata/socialtestdb.json");

   bind(ActivityService.class).to(JsonDbOpensocialService.class);
   bind(AppDataService.class).to(JsonDbOpensocialService.class);
   //bind(PersonService.class).to(JsonDbOpensocialService.class);
   bind(PersonService.class).to(SocialTestJsonPersonService.class);

   bind(MessageService.class).to(JsonDbOpensocialService.class);

   bind(OAuthDataStore.class).to(SampleOAuthDataStore.class);

   // We do this so that jsecurity realms can get access to the  jsondbservice singleton
   requestStaticInjection(SampleRealm.class);
  }
  ……
  }

從清單 2 中,還可以看到,標記為"shindig.socialtest.json.db"的字符串綁定到 了"sampledata/socialtestdb.json", socialtestdb.json 是我們示例中的 JSON 數據文件,用來保存 People 數據。在 SocialTestJsonPersonService 的實現中,db.getJSONArray(PEOPLE_TABLE) 就是從該 JSON 文件獲取所有的 People 數據。

在下一節,我們給出客戶端實現,來消費 socialtestdb.json 中的 Social 數據。

Gadget/Restful 客戶端實現

Gadget 實現

清單 3. SocialAppTest.xml

<?xml version="1.0" encoding="UTF-8"?>
  <Module>
   <ModulePrefs
       title="Social Application Test"
       author_email="[email protected]">
       <Require feature="osapi" />
       <Require feature="dynamic-height" />
   </ModulePrefs>
   <Content type="html" ><![CDATA[<!-- Fetching People and Friends -- >
  <div>
  <button onclick='fetchPeople();'>Fetch people and friends</button>
  <div>
   <span id='viewer'></span>
   <ul id='friends'></ul>
  </div>
  </div>
  <script type='text/javascript'>
  var allPeople;
  function render(data) {
   var viewer = data.viewer;
   allPeople = data.viewerFriends.list;

   document.getElementById('viewer').innerHTML = viewer.id;
   document.getElementById('friends').innerHTML = '';
   for (var i = 0; i < allPeople.length; i++) {
    document.getElementById('friends').innerHTML += '<li>' +
                         allPeople[i].name.formatted +  '</li>';
   }
   gadgets.window.adjustHeight();
  }

  function fetchPeople() {
   var fields = ['id','age','name','gender','profileUrl','thumbnailUrl'];
   var batch = osapi.newBatch();
   batch.add('viewer', osapi.people.getViewer({sortBy:'name',fields:fields}));
   batch.add('viewerFriends',
        osapi.people.getViewerFriends({sortBy:'name',fields:fields}));
   batch.add('viewerData', osapi.appdata.get({keys:['count']}));
   batch.add('viewerFriendData',
        osapi.appdata.get({groupId:'@friends',keys:['count']}));
   batch.execute(render);
  }

  </script>]]></Content>
  </Module>

如清單 3 所示,fetchPeople 使用了 osapi 獲得 OpenSocial 數據,並把它們展示在 HTML 頁面上 。osapi 是一個輕量級的 JavaScript 類庫,用於幫助客戶端獲得 OpenSocial 數據。顯示該 Gadget 的 HTML 頁面代碼 (socialtest.html),請讀者詳見文章後面的資源類表,在這裡我們就不一一列出。

現在,我們可以在 Eclipse IDE 中啟動 Shindig, 在你的浏覽器裡輸入地址:

http://localhost:8080/gadgets/files/samplecontainer/socialtest.html,打開 SocialAppTest Gadget,點擊”Fetch people and friends”按鈕,SocialAppTest Gadget 向本地 Shindig 請求數據, Shindig 從 socialtestdb.json JSON 文件中獲取數據,返回給 Gadget, 並在浏覽器中顯示,如圖 4 所 示:

圖 4. SocialAppTest Gadget

RESTful 客戶端實現

另外,我們還可以選擇使用 Java 應用程序,通過 REST 協議獲得 OpenSocial 數據,如清單 4 所示 。

清單 4. RESTful Client 實現

public class SocialAppTest {
   private static final String BASE_URI =  "http://localhost:8080/social/rest/";

   private static final String VIEWER_ID = "john.doe";

   public static void main(String[] args) {
     OpenSocialClient client = new OpenSocialClient("SocialAppTest");
     client.setProperty(OpenSocialClient.Property.REST_BASE_URI, BASE_URI);
     client.setProperty(OpenSocialClient.Property.VIEWER_ID, VIEWER_ID);
     try {
       OpenSocialPerson viewer = client.fetchPerson(VIEWER_ID);
       System.out.println("Viewer: " + viewer.getId());
       Collection<OpenSocialPerson> friends = client.fetchFriends (viewer.getId());
       for (OpenSocialPerson friend : friends) {
         System.out.println("Friend: " + friend.getId());
       }
     } catch (Exception e) {
       e.printStackTrace();
     }
   }
  }

清單 4 的運行結果和 SocialAppTest Gadget 一樣,顯示當前的 Viewer 及其他的朋友。

結束語

通過本文,讀者已經了解了如何使用 Shindig SPI 來將自己的 Social 數據適配到 Shindig 平台, 也了解了如何構建客戶端的應用來消費這些 Social 數據。

現在,我們不妨回頭總結一下整個 OpenSocial 平台的系統結構。一般來說,OpenSocial 系統應用使 用 OpenSocial   Gadget 作為應用前端,OpenSocial Gadget 類似於 iGoogle Gadget,不過增加了 OpenSocial 數據的訪問能力。當然,你也可以使用基於 REST/RPC 協議構建的桌面 RCP 應用作為前端。 而對於 OpenSocial 平台服務器端,也有兩個選擇,一則如本文所討論的這樣,利用成熟開源的,與 OpenSocial 規范相兼容的 OpenSocial 容器實現 ( 例如 Shindig),通過 SPI 擴展實現自己的 OpenSocial 容器,或者你從頭開始實現 OpenSocial 規范相兼容的 OpenSocial 容器。

隨文源碼:http://www.bianceng.net/java/201212/689.htm

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved