必要なもの:
このチュートリアルで作成されたウィジェットとオペレータのリファレンス実装は、 次の github リポジトリにあります :
https://github.com/wirecloud-fiware/quick-start-development-tutorial
チュートリアルを完了した後、またはストールした場合に備えて、 リファレンス実装を見ることをお勧めします。
最初のステップは空のウィジェットを作ることです。メタデータと基本的な HTML を定義したものです。メタデータは config.xml ファイルに書き込まれます。 これは次のような内容です :
<?xml version='1.0' encoding='UTF-8'?>
<widget xmlns="http://wirecloud.conwet.fi.upm.es/ns/macdescription/1" vendor="CoNWeT" name="basic-chat" version="0.1">
<details>
<title>Basic chat</title>
<homepage>https://github.com/wirecloud-fiware/quick-start-development-tutorial</homepage>
<authors>Miguel Jimenez <mjimenez@fi.upm.es></authors>
<contributors>Álvaro Arranz <aarranz@fi.upm.es></contributors>
<email>wirecloud@conwet.com</email>
<image>images/chat_logo.png</image> <!-- 170x80 -->
<description>Basic chat functionality and WireCloud features demonstrator</description>
<longdescription>README.md</longdescription>
<license>Apache License 2.0</license>
<licenseurl>http://www.apache.org/licenses/LICENSE-2.0.html</licenseurl>
<doc>doc/developer-guide.md</doc>
</details>
<contents src="index.html" useplatformstyle="true"/>
<rendering width="5" height="24"/>
</widget>
そのテンプレートは、Markdown を使って書くことができるより詳細な説明と共に、 著者/ベンダーのようなウィジェットのメタデータを示します。
ルート要素の属性として示されている vendor
, name
そして version
に注意してください。WireCloud の設定によっては、同じバージョン/名前/ベンダーの
ウィジェットを2回アップロードすることが許可されないので、ウィジェットの
新しいバージョンをアップロードするには、バージョン、サブバージョン、
またはリビジョン番号を増やす必要があります。さらに、他のユーザがすでに
バージョン、名前、およびベンダーが同じウィジェットをアップロードした場合、
WireCloud はウィジェットをアップロードしないため、ベンダーを変更する必要が
あります。
2つ目に注目すべき要素は、rendering
要素です。ウィジェットのサイズに
関する基本情報と、メインの HTML ファイルへの参照を含む要素です。
このようなファイルはウィジェットへのエントリポイントとなり、JavaScript
または CSS ファイルへの参照を含みます。
config.xml
に index.html
という名前で示されている基本的な HTML
を以下に示します。このドキュメントには、ユーザの写真とニックネームの
基本ヘッダー、メッセージのパネル、およびメッセージ送信の基本フォームが
含まれています。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8"></meta>
<script type="text/javascript" src="js/main.js"></script>
<link rel="stylesheet" type="text/css" href="css/style.css" />
</head>
<body>
<div id="header">
<img id="photo"id="photo" alt="Profile photo" max-height="60" max-width="60" />
<h2 id="username">Username</h2>
</div>
<div id="conversations"></div>
<div id="footer">
<input id="input" type="text" /><button id="send" type="button">Send</button>
</div>
</body>
</html>
この HTML コードは js/main.js
JavaScript ファイルを参照します。
JavaScript ファイルには必要なコードが含まれています。JavaScript
コードについては後で詳しく説明します。さらに、チャット・アプリケーションの
基本的なスタイルを含む CSS ファイルが参照されています。
body { padding: 0;
margin: 0;
font-family: sans-serif;
color: #333;}
#photo {padding: 3px;
border: 2px solid #eaeaea;
max-height: 48px;
max-width: 48px;
float:left;}
.sent, .received {
min-height: 36px;
padding: 2px;
border: 1px solid #eaeaea;
border-radius: 5px;}
.sent { margin: 1px 35px 1px 1px;}
.received{ margin: 1px 1px 1px 35px;
text-align: right;}
.received > p{ display: inline;}
.sent > img{ max-height: 28px;
max-width: 28px;
margin: 2px;
float:left;}
.sent > p{ display:inline;}
.received > img{ max-height: 28px;
max-width: 28px;
margin: 2px;
float:right;}
#username { display: inline;}
#conversations { height: 65%;
overflow: scroll;}
#footer{position: fixed;
bottom: 0;}
#header{height:60px;}
body,html { height: 100%;}
最後に、参照先のjs/main.js
が作成されます。ここでは、クロージャー、
init()
関数、そして HTML インターフェースを扱うための
2つの関数のようないくつかの基本的な要素を含みます。
(function() {
"use strict";
// object with the data received from gravatar
var userData = null;
function init() {
document.getElementById("send").onclick = sendBtnHandler;
getInfoFromGravatar();
}
function sendBtnHandler(e) {
}
function createMsgDiv(text,imageSrc,received,id){
var newMsgP = document.createElement('p');
var newMsgImg = document.createElement('img');
var newMsgDiv = document.createElement('div');
newMsgP.innerHTML = text;
newMsgP.id = id;
newMsgImg.src = imageSrc;
newMsgImg.alt = 'User profile img';
newMsgDiv.className=(received)?'received':'sent';
newMsgDiv.appendChild(newMsgImg);
newMsgDiv.appendChild(newMsgP);
var conversations = document.getElementById('conversations');
conversations.appendChild(newMsgDiv);
conversations.scrollTop = newMsgDiv.offsetTop;
}
function getInfoFromGravatar() {
// Put the info in userData variable
}
function printUserData(user_data) {
document.getElementById('username').innerHTML = user_data.entry[0].displayName;
document.getElementById('photo').src = user_data.entry[0].thumbnailUrl;
}
document.addEventListener('DOMContentLoaded', init.bind(this), true);
})();
最初に追加する機能は設定です。Widget の設定は config.xml
で宣言する必要があり、
後で、WireCloud JavaScript API を介してアクセスされます。ユーザの gravatar
プロファイルを取得するための設定の宣言は、次のようになります :
<preferences>
<preference name="gravatar" type="text" label="Gravatar URL" description="URL to the gravatar profile of the user" />
</preferences>
この <preferences>
セクションはルート要素 <widget>
の内側になければなりません。
これで、選択した name
を使ってその値にアクセスできます。次の行は
getInfoFromGravatar()
関数内にあるため、特定の URL に HTTP リクエストを送信できます。
var gravatarURL = MashupPlatform.prefs.get('gravatar');
これだけをした場合、ユーザが自分のプロフィールを表示すると、Gravatar
からプロフィールを取得するためにウィジェットをリロードする必要があります。
賢く物事をやるために、どんな設定変更についてもプラットフォームから通知され、
それに応じて反応しています。この場合は、getInfoFromGravatar()
をもう一度呼び出します。 次のコードはinit()
関数の中に入ります :
MashupPlatform.prefs.registerCallback(function(new_values) {
if ('gravatar' in new_values) {
getInfoFromGravatar();
}
});
ユーザから他の情報を収集するために HTTP リクエストを送信します。
Gravatar は JSON バージョンのプロファイルを同じ URL で提供し、拡張子
.json
を追加します。そのため、それがリクエストのベース URL になります。
基本的な HTTP リクエストは次のようになります :
MashupPlatform.http.makeRequest(url, {
method: 'GET',
onSuccess: function(response) {
var user_data;
user_data = JSON.parse(response.responseText);
if (user_data.error) {
// handle error
onError();
} else {
// perform actions
}
},
onError: function() {
onError();
}
});
この構造は、取得したユーザ設定 gravatarURL
と文字列 json
を連結した結果の
URL で呼び出されます。実行されるアクションは、userData
変数にデータを格納し、
以前に作成した printUserData()
関数を使用してそれをウィジェットに
表示させることです :
var url = gravatarURL + '.json';
...
onSuccess: function(response) {
var user_data;
user_data = JSON.parse(response.responseText);
if (user_data.error) {
onError();
} else {
userData = user_data;
printUserData(user_data);
}
}
gravatar から取得した userData
は、例えば print UserData()
のように、
その情報にアクセスするために使われる単純な構造を持ちます :
{
"entry": [{
"id": "9508921",
"hash": "61ac3cca6452efd339cb85c7864c147b",
"requestHash": "mjimenezganan",
"profileUrl": "http:\/\/gravatar.com\/mjimenezganan",
"preferredUsername": "mjimenezganan",
"thumbnailUrl": "http:\/\/2.gravatar.com\/avatar\/61ac3cca6452efd339cb85c7864c147b",
"photos": [{
"value": "http:\/\/2.gravatar.com\/avatar\/61ac3cca6452efd339cb85c7864c147b",
"type": "thumbnail"
}],
"name": {
"givenName": "Miguel",
"familyName": "Jim\u00e9nez"
},
"displayName": "mjimenezganan",
"aboutMe": "More info on www.twitter.com\/miguel_jimg",
"currentLocation": "Spain",
"urls": []
}]
}
ウィジェットのチャット機能は、WireCloud のワイヤリング・メカニズムを
介して行われます。まず最初に、入力エンドポイントと出力エンドポイントを
config.xml
ファイルで宣言する必要があります :
<wiring>
<outputendpoint name="sendMsg" type="text" label="Send a message" description="The messages sent by the user are sent through this output endpoint" friendcode="message"/>
<inputendpoint name="receiveMsg" type="text" label="Receive a message" description="This is where messages sent by other widgets can be received" friendcode="message" />
</wiring>
メッセージの送信は、宣言されたとおりに出力エンドポイント名をリファレンスする
MashupPlatform.wiring.pushEvent()
関数を呼び出すことを意味します。
MashupPlatform.wiring.pushEvent('sendMsg', text);
sendBtnHandler()
に追加します。メタデータ、つまり送信者の画像を取得することを
可能にする Gravatar ハッシュを含むメッセージを送信できるようにするために、
JSON シリアライズ。オブジェクトが送信されます :
function sendBtnHandler(e) {
var msgToSend = {};
msgToSend.msg = document.getElementById("input").value;
if (msgToSend.msg !== "" && userData != null) {
msgToSend.hash= userData.entry[0].hash;
MashupPlatform.wiring.pushEvent('sendMsg', JSON.stringify(msgToSend));
}
}
メッセージはワイヤリングを通じて送信されますが、ウィジェットは他のウィジェットの
メッセージを受信して会話パネルに表示する必要があります。これはプラットフォーム上で
コールバック関数を登録することで実行され、特定の入力エンドポイントで受信された
メッセージを登録します。その名前で識別されます。
init()
機能で、次のように記述します :
MashupPlatform.wiring.registerCallback('receiveMsg', processMsg);
そして、望ましい振る舞いを示すために processMsg()
関数を作成しなければなりません。
今回の場合は、会話パネルでメッセージを作成します。メッセージはシリアライズされた
JSON オブジェクトとして送信されるため、それらの要素にアクセスするために
デシリアライズされます。それは自身のメッセージを検出しそれらを異なった CSS
スタイルを送信したように表示するので、少しトリッキーです。これがエコーの動作です。
function processMsg(event_data) {
var receivedMsg = JSON.parse(event_data);
if (userData != null && receivedMsg.hash !== userData.entry[0].hash) {
createMsgDiv(receivedMsg.msg, 'http://www.gravatar.com/avatar/' + receivedMsg.hash, true, receivedMsg.id);
} else { // My message, echo, mark as sent
createMsgDiv(receivedMsg.msg,'http://www.gravatar.com/avatar/' + receivedMsg.hash, false, receivedMsg.id);
document.getElementById(receivedMsg.id).parentElement.className = 'sent';
}
}
オペレータは config.xml
宣言ファイルで定義され、その動作を含む
1つまたは複数の JavaScript ファイルを参照します。
ウィジェットと同様に、config.xml
には、競合や WireCloud
によるオペレータの拒否を避けるために、ベンダー、名前、および
バージョン情報を更新する必要があります。
<?xml version='1.0' encoding='UTF-8'?>
<operator xmlns="http://wirecloud.conwet.fi.upm.es/ns/macdescription/1"
vendor="CoNWeT" name="ngsi-chat-op" version="0.1.1">
<details>
<title>NGSI chat operator</title>
<homepage>https://github.com/wirecloud-fiware/quick-start-development-tutorial</homepage>
<authors>Miguel Jiménez</authors>
<email>mjimenez@fi.upm.es</email>
<image>images/operator_logo.png</image> <!-- 170x80 -->
<description>Connect to Orion Context Broker through NGSI WireCloud API for chat room</description>
<longdescription>README.md</longdescription>
<license>Apache License 2.0</license>
<licenseurl>http://www.apache.org/licenses/LICENSE-2.0.html</licenseurl>
<doc>doc/developer-guide.md</doc>
</details>
<scripts>
<script src="js/main.js"/>
</scripts>
</operator>
このウィジェットには、NGSI サーバの URL を簡単に示すための設定と、ウィジェット/
オペレータからアクセスするためのプロキシがあります。
さらに、chatroom
設定が追加されました。
<preferences>
<preference name="ngsi_server"
type="text" label="NGSI server URL"
description="URL of the Orion Context Broker to use for retrieving entity information"
default="http://orion.lab.fiware.org:10026/"/>
<preference name="ngsi_proxy"
type="text"
label="NGSI proxy URL"
description="URL of the PubSub Context Broker proxy to use for receiving notifications about changes"
default="https://ngsiproxy.lab.fiware.org/"/>
<preference name="chatroom"
type="text"
label="Chat room"
description="Chat room to send and receive messages"
default="Startup Weekends"/>
</preferences>
ワイヤリングもウィジェットで使用されています。受信したメッセージをウィジェットに 送り返し、ユーザ・メッセージを NGSI API に転送します :
<wiring>
<outputendpoint name="toBeReceived"
type="text"
label="Messages from NGSI"
description="Forward a message to a chat widget"
friendcode="message" />
<inputendpoint name="toBeSent"
type="text"
label="Message to NGSI"
description="Receive messages to be sent to the chat room"
friendcode="message" />
</wiring>
基本的な JavaScript ファイルは以下に書かれていて、初期化機能、設定とワイヤリング、 サブスクリプションといくつかのスケルトンを含みます:
(function() {
"use strict";
var chatroom = null;
var ngsi_connection = null;
function init() {
MashupPlatform.wiring.registerCallback('toBeSent', publishMsg);
MashupPlatform.prefs.registerCallback(function(new_values) {
if ('chatroom' in new_values) {
subscribeChatRoom();
}
});
subscribeChatRoom();
}
function publishMsg(event_data) {
}
function subscribeChatRoom() {
}
function receiveMessage(data){
for(var msg in data.elements){
MashupPlatform.wiring.pushEvent('toBeReceived', JSON.stringify(data.elements[msg]));
}
}
init();
})();
まず、config.xml
ファイル内で NGSI を必須機能として宣言する必要があります :
<requirements>
<feature name="NGSI"/>
</requirements>
NGSI 接続はそれを介してリクエストを行うために安定させる必要があります。 WireCloud にログオンしたユーザからの FIWARE トークンを使用して認証しています。 それを保持し、他の関数からアクセスするためのグローバル (クロージャ) 変数を宣言しました。
ngsi_connection = new NGSI.Connection(MashupPlatform.prefs.get('ngsi_server'), {
use_user_fiware_token: true,
ngsi_proxy_url: MashupPlatform.prefs.get('ngsi_proxy')
});
新しいエンティティを作成したり、既存のエンティティを変更するには、接続の機能
addAttributes()
が使用されます。チャット・アプリケーションの場合は、hash
と msg
属性を使用して、ワイヤリングによって送信されるイベントとまったく
同じように、クラス ChatMessage
の新しいインスタンスが作成されます。
詳細情報は、
WireCloud ドキュメントの NGSI API
、または
WireCloud を使った Orion Context Broker チュートリアル
にあります。
作成するエンティティはこのようなものです :
[{
entity: {id: MashupPlatform.prefs.get('chatroom') + now.getTime() + msg.hash,
type: 'ChatMessage'},
attributes: [
{
type: 'string',
name: 'hash',
contextValue: msg.hash
},
{
type: 'string',
name: 'msg',
contextValue: msg.msg
}]
}]
完全な publishMsg()
の定義は次のようになります :
function publishMsg(event_data) {
var now = new Date();
var msg = JSON.parse(event_data);
ngsi_connection.addAttributes([{
entity: {id: MashupPlatform.prefs.get('chatroom') + now.getTime() + msg.hash,
type: 'ChatMessage'},
attributes: [
{
type: 'string',
name: 'hash',
contextValue: msg.hash
},
{
type: 'string',
name: 'msg',
contextValue: msg.msg
}]
}]);
}
エンティティの ID は、固定部分 (チャットルームを示す設定) に加えて、 タイムスタンプとユーザ作成のハッシュを使用して作成されています。
このオペレータは、ChatMessageID がチャット・ルームで始まるすべてのタイプの インスタンスの変更 (作成は変更の一種です) を受け取ります。以前に (chatroom 変数に格納された) サブスクリプションを作成したことがある場合、 それをキャンセルします。
サブスクリプション自体が createSubscription()
メソッドを呼び出して作成されます。これはいくつかのパラメータ
(監視するエンティティの ID、あなたが興味を持っている属性のリスト、
サブスクリプションの期間など) を必要とします、
次のスライドでこのシナリオのための使用例を示します。
function subscribeChatRoom() {
if (chatroom != null) {
NGSI.cancelSubscription(chatroom);
}
var entityIdList = [
{type: 'ChatMessage', id: MashupPlatform.prefs.get('chatroom') + '.*', isPattern: true}
];
var attributeList = null;
var duration = 'PT30M';
var throttling = null;
var notifyConditions = [{
type: 'ONCHANGE',
condValues: ['hash', 'msg']
}];
var options = {
flat: true,
onNotify: receiveMessage,
onSuccess: function (data) {
chatroom = data.subscriptionId;
}
};
ngsi_connection.createSubscription(entityIdList, attributeList, duration, throttling, notifyConditions, options);
}
サブスクリプション期間は30分に設定されており、それより前に更新、またはページの リロードをする必要があります。サブスクリプションを更新する方法は、 このチュートリアルの将来のバージョンで示される予定です。それまでの間、 これ行う方法の一般的なチュートリアルについては WierCloud を使った Orion Context Broker チュートリアル をご覧ください。
目次 | t |
---|---|
スライド一覧 | ESC |
フルスクリーン | e |
発表者ビュー | p |
ソースファイル | s |
スライド番号 | n |
画面ブランキングの切り替え | b |
スライド・コンテキストの表示/非表示 | c |
ノート | 2 |
ヘルプ | h |