什麼是 OpenSocial
OpenSocial 是基於開放標准的一組通用的 API用於幫助 WEB 的開發者構建跨多個社交網站的可移植的社交應用程序OpenSocial 提供開發者一套通用的 API基於該通用 API 開發的社交應用程序可以運行在任意支持 OpenSocial 規范的社交網站上
關於更多的有關 OpenSocial 內容請讀者參見
Apache Shindig
Shindig 是 OpenSocial 規范的引用實現其主要的組件包括 :
Gadget Container JavaScriptOpenSocial Gadget 容器客戶端的 JavaScript 類庫 (gadgetjs)提供例如 UI LayoutSecurity 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 等相關的社交數據
圖 是 Shindig 的服務器端架構圖
圖 Shindig Architecture( 引自 Chris Schalk@GoogleTM)
從圖 中可以看到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 內容請讀者參見
Eclipse 環境下編譯 / 調試 Shindig
我們通過以下的步驟來完成
安裝 Maven plugin
Maven 是一個基於 Java 的代碼構建和依賴管理工具Apache Shindig 的源代碼是通過 Maven 來管理的所以我們需要安裝 Maven 的 Eclipse 插件讀者可以使用 Eclipse 的 updatesite 機制連接到站點安裝
使用 Subversion 下載 Shindig 代碼
在 使用 SVN 客戶端下載到 Shindig 的源代碼
編譯和調試 Shindig
首先在 Eclipse IDE 裡通過 File/Import/General/Maven Projects 選項導入我們下載的所有 Shindig 的源代碼導入完成後Shindig 就作為幾個 Maven 工程存在於你當前的 WorkSpace 中
通過 Run/Debug Configurations/Maven Build 配置編譯 Shindig 參數如圖 所示
圖 Package Shindig
如圖 所示E:\svn_repository\opensocialshindig是你的 Shindig 源代碼的根目錄點擊 Debug 這將使用 Maven 來 Build 整個 Shindig 代碼在 Build 成功後我們使用 Jetty 來啟動 Shindig默認情況下Jetty Server 將運行在 端口如圖 所示
圖 Run Shindig
如圖 所示我們設置了 Maven 目標使用 Jetty 來啟動 Shindig 而 Base directory 設置為 shindigserver Maven 工程的根目錄點擊 Debug Jetty Server 運行而 Shindig 部署在 Jetty Server 上 在 Shindig 成功啟動後 你就可以使用//localhost:/gadgets/files/samplecontainer/l來訪問 Shindig 提供的 Gadget 的例子
Shindig 服務器端 SPI 擴展
Shindig 作為 OpenSocial 規范的引用實現提供了 SPI 的擴展能力允許你把數據適配到 Shindig 容器中去你的這些數據也許存在於諸如 My SQL/Oracle 的關系數據庫或者是以 JSON 格式存儲的靜態文件無論哪種存儲你都可能通過 Shindig SPI 將它們適配到 Shindig 從而使這些數據公布在 OpenSocial 平台上
圖 Shindig SPI 擴展
如圖 所示你的應用需要實現 ActivityService PersonService AppDataService 三個接口利用諸如 JDBC/Hibernate 等機制把數據提供給 Shindig
接下來本文將通過一個例子實現 PersonService 接口向 Shindig 提供 People/Friends 相關的 OpenSocial 數據
清單 是 SocialTestJsonPersonService類的實現
清單 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 =
; i < people
length(); i++) {
JSONObject person = people
getJSONObject(i);
if (!ntains(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 =
; 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);
}
}
……
}
從清單 可以看到SocialTestJsonPersonService 實現了 PersonService 兩個接口方法 getPeople 及其 getPersongetPeople 根據傳入參數 userIds返回相應於該 ID 列表的用戶列表而 getPerson 根據傳入參數 id返回相應於該 ID 的用戶
注意Shindig 依賴 Guice 做動態的依賴注入 (dependency Injection)我們需要在 orgapacheshindigsocialsampleSampleModule 裡指示 Guice 把 PersonService 綁定到 SocialTestJsonPersonService 實現如清單 所示
清單 SampleModule Class
public class SampleModule extends SocialApiGuiceModule {
@Override
protected void configure() {
nfigure();
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);
}
……
}
從清單 中還可以看到標記為shindigsocialtestjsondb的字符串綁定到了sampledata/socialtestdbjson socialtestdbjson 是我們示例中的 JSON 數據文件用來保存 People 數據在 SocialTestJsonPersonService 的實現中dbgetJSONArray(PEOPLE_TABLE) 就是從該 JSON 文件獲取所有的 People 數據
在下一節我們給出客戶端實現來消費 socialtestdbjson 中的 Social 數據
Gadget/Restful 客戶端實現
Gadget 實現
清單 SocialAppTestxml
<?xml version=
encoding=
UTF
?>
<Module>
<ModulePrefs
title=
Social Application Test
author_email=
>
<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 =
; 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>
如清單 所示fetchPeople 使用了 osapi 獲得 OpenSocial 數據並把它們展示在 HTML 頁面上osapi 是一個輕量級的 JavaScript 類庫用於幫助客戶端獲得 OpenSocial 數據顯示該 Gadget 的 HTML 頁面代碼 (l)請讀者詳見文章後面的資源類表在這裡我們就不一一列出
現在我們可以在 Eclipse IDE 中啟動 Shindig 在你的浏覽器裡輸入地址
//localhost:/gadgets/files/samplecontainer/l打開 SocialAppTest Gadget點擊Fetch people and friends按鈕SocialAppTest Gadget 向本地 Shindig 請求數據Shindig 從 socialtestdbjson JSON 文件中獲取數據返回給 Gadget 並在浏覽器中顯示如圖 所示
圖 SocialAppTest Gadget
RESTful 客戶端實現
另外我們還可以選擇使用 Java 應用程序通過 REST 協議獲得 OpenSocial 數據如清單 所示
清單 RESTful Client 實現
public class SocialAppTest {
private static final String BASE_URI = //localhost:
/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();
}
}
}
清單 的運行結果和 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 容器
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26538.html