Platform Event の購読と公開を Visualforce で実装(Apexも)

##Visualforce ページから Platform Event を購読 
- Visualforce ページで Platform Event を購読するために、Streaming API を利用します。
- 対して Visualforce ページで Platform Event を公開するために、Rest API を利用します。
- Streaming API 実装方法の情報少なすぎ＼(^o^)／

###CometD のライブラリを含む静的リソースを準備
- まずは Streaming API を利用するのに必要な以下のファイルをまとめて静的ソースにアップロードしておきます。
- [CometD のバージョンは3.1.0以上との指定がある](https://help.salesforce.com/articleView?id=000265558&language=ja&type=1)ので気を付けてください。

| js ファイル           | 取得元 |
|:-------------------|:-------------------------|
|cometd.js           | [CometD の Download ページ](https://download.cometd.org/) からダウンロードした cometd-3.1.X-distribution.tar.gz を展開後、cometd-javascript/jquery/target　にある .war ファイルを展開 |
|jquery-3.2.1.min.js | [jQuery CDN – Latest Stable Versions](https://code.jquery.com/) |
|jquery.cometd.js    | [CometD の Download ページ](https://download.cometd.org/) からダウンロードした cometd-3.1.X-distribution.tar.gz を展開後、cometd-javascript/jquery/target　にある .war ファイルを展開 |

- こんな感じ

<img width="480" alt="スクリーンショット 2017-11-15 10.36.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/26378/30dd3e90-4c76-c01d-b53d-ffb2279bd3aa.png">



###Visualforce での実装例
- 事前に作成しておいた、`ExampleEvent__c`　という Platform Event を購読するサンプルプログラムです。

```html:PlatformEventSubscribeExample.vfp
<apex:includeScript value="{!URLFOR($Resource.PlatformEventExample, 'asset/js/cometd.js')}"/>
<apex:includeScript value="{!URLFOR($Resource.PlatformEventExample, 'asset/js/jquery-3.2.1.min.js')}"/>
<apex:includeScript value="{!URLFOR($Resource.PlatformEventExample, 'asset/js/jquery.cometd.js')}"/>

<script>
    /*** Streaming API によるイベントの購読 ***/ 
    $(document).ready(function() {

        // Websocket はサポートされていないらしい
        $.cometd.websocketEnabled = false;

        $.cometd.configure({
            url: window.location.protocol + '//' + window.location.hostname + '/cometd/41.0/',
            requestHeaders: { Authorization: 'OAuth {!$Api.Session_ID}'}
        });

        // 握手が成功してから購読開始
        $.cometd.handshake(function(handshakeReply) { 
            if(handshakeReply.successful) { 
                $.cometd.subscribe('/event/ExampleEvent__e', function(message) {
                    console.log(message.data.payload);
                });
            } else {
                console.error(handshakeReply);
            }
        });
    });
    // Window が閉じられる前に、購読を停止する
    window.onbeforeunload = function () {
        $.cometd.disconnect();
    };
</script>

```

##Visualforce ページから Platform Event を公開
- 通常の Rest API による Plateform Event の公開例です。

###Visualforce での実装例
```html:PlatformEventPublishExample.vfp

<script>
    /*** Rest API によるイベントの公開 ***/ 
    function publishExampleEvent() {
        var xhr = new XMLHttpRequest();
        xhr.open('POST', window.location.protocol + '//'+ window.location.hostname +'/services/data/v41.0/sobjects/ExampleEvent__c');
        xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
        xhr.setRequestHeader('Authorization', 'Bearer {!$Api.Session_ID}');
        xhr.onreadystatechange = function () {
            if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 201) {
                response = JSON.parse(xhr.responseText);
                if (response.success) {
                    alert('SUCCESS');
                } else {
                    alert('ERROR');
                    console.error(response.warnings);
                    console.error(response.errors);
                }
                
            } 
        };
        xhr.send(JSON.stringify({CustomField1__c: 'Value1', CustomField2__c: 'Value2'}));
    }
</script>

```

##Apex から Platform Event を公開
- Apex から　Platform Event を公開したい場合は以下の実装が可能です。

```java:PlatformEventPublishExample.apxc
ExampleEvent__c event = new ExampleEvent__c(CustomField1__c='Value1', CustomField2__c='Value2');
Database.SaveResult sr = EventBus.publish(event);
if (sr.isSuccess()) {
    System.debug('Successfully published event.');
} else {
    for(Database.Error err : sr.getErrors()) {
        System.debug('Error returned: ' +
                     err.getStatusCode() +
                     ' - ' +
                     err.getMessage());
    }
}
```