PubNubをApache Camelからサクッと使ってWebsocket代替にする

皆さんこんにちは。しうへいと申します。
今回はIoT向けBaaSであるPubNubに、Apache Camelから接続する方法について書きます。

## PubNubを知った経緯
昨日3/11になりますが、[集まれMilkcocoaオジサン。 Milkcocoa Meetup vol 8](http://mlkcca.connpass.com/event/27083/) という勉強会に参加してきました。

IoT向けBaaSとして[Milkcocoa](https://mlkcca.com/) の名前を最近よく聞いていたのと、自分自身その分野のサービスに興味があったので参加しましたが、スピーカーの皆さんが話される内容としては、そのままズバリIoTというよりは、MilkcocoaのリアルタイムWebサーバーとしての機能を活用したものが多く（もちろんセンサー系のデモもありました）、期待してたものと少し違ったかなぁ…と思っていました。

そんな折、最後のスピーカーとして、Milkcocoaエバンジェリストであるのびすけ[@n0bisuke](https://twitter.com/n0bisuke)さんが、おもむろに

「PubNubって知ってる？」
「PubNubってイケてるらしいよ？」
「Milkcocoaは正直負けてるかもしんない」
「でも同じBaaSとして一緒に盛り上がっていけたらいいと思うんだよね」

（※記憶力ないので、ニュアンスで書いてます）

（追記）
のびすけさんから実際のスライドのURLをいただきましたので、こちらに関してはスライドをご覧ください。
https://speakerdeck.com/n0bisuke/pubnubtomilkcocoa-milkcocoameetup-vol9-number-mlkcca-5fen
（追記ここまで）

みたいな話をされて、ロックなエバンジェリストだなぁと思いつつ、そこで[PubNub](https://www.pubnub.com/)を知ることになりました。



## リアルタイムWebサーバーをBaaSに移譲するというトレンド

「Backend as a Service」 という言葉の響きからは、自分はもっと大仰なものをイメージしていたのですが、もっとカジュアルに、リアルタイムWebサーバーとして使えばいいんじゃないの、というメッセージをスピーカーの皆さんから受信しました。最初は「それならApache CamelのWebsocketコンポーネントがあるからいいかなぁ」と思っていましたが、Websocketを実際扱う際の泥臭さは知るところでしたので、その部分だけ定評のある外部サービスに移譲するのも良いのかと思うようになりました。

## PubNubには、Apache Camel向けのコンポーネントがすでにあった

Apache Camelについて簡単に説明すると、Javaプラットフォームで動作する、ライブラリ / サービス / フォーマット / プロトコル統合フレームワークです。ライブラリ / サービス / フォーマット / プロトコル同士の、n対nの接続および変換コードを個々に書くのは大変だから、n-x-nになるようなxを作ろう、みたいな発想から生まれたフレームワークです。

ちなみにApache Camelでは、n-xの部分をコンポーネントと呼んでいます。
2016年3月現在、コンポーネントはプロジェクトの外部で作られたものも合わせて200以上に達しています。

Apache Camel: Components http://camel.apache.org/components.html

驚くことに、今日知ったばかりのPubNubは、外部で作られたコンポーネントとして、既に上記に掲載されていました。
Camelライダーとしては、これは試してみるっきゃありません。

## PubNubを使う準備をする

PubNub https://www.pubnub.com/
![無題.png](https://qiita-image-store.s3.amazonaws.com/0/105865/ca0c2b45-8c56-d9d9-4f1c-2344f1c75b97.png)

登録に必要なのはメールアドレスくらいでした。
特につまづきポイントなく登録が完了したので割愛します。

## PubNubアプリケーションを作成して、キーを入手
ログインして [CREATE NEW APP]ボタンからアプリケーションを作成して、適当な名前をつけます。自分は「myiot」としました。
<img width="1280" alt="無題2.png" src="https://qiita-image-store.s3.amazonaws.com/0/105865/c5ae7938-dc0d-fc1e-7f1f-822ea3588b29.png">

アプリケーションの詳細に入っていくと、各種キー情報が表示されます。これでPubNub側は準備完了です。

<img width="1280" alt="無題3.png" src="https://qiita-image-store.s3.amazonaws.com/0/105865/82d5ce15-f472-4365-7b0c-df339e1ca130.png">

## Apache Camelを使う準備をする

IDE上でMavenプロジェクトを新規作成して、依存関係を記述します。
（自分は標準でビルドツールMavenが入っているNetBeans IDEを使ってます）
セントラル・リポジトリでcamel-pubnubと検索して、追加すれば良いです。
Apache Camel側のissueで、slf4j-simpleも追加します。これで標準出力にログが出力されます。

以下は自動生成されたpom.xmlです。

```xml:pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycode</groupId>
    <artifactId>myiot</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>io.rhiot</groupId>
            <artifactId>camel-pubnub</artifactId>
            <version>0.1.4</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.6.6</version>
        </dependency>
    </dependencies>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
</project>
```

## PubNubコンポーネントの使い方を確認する

以下にcamel-pubnubコンポーネントの使い方が書いてあります。
https://rhiot.gitbooks.io/rhiotdocumentation/content/cloudplatform/camel_components/camel_pubnub_component.html
Apache CamelではアクセスするリソースをURIとして記述する必要があります。この書き方が分かればよいので、General URI formatの辺りに目を通します。
<img width="640" alt="無題4.png" src="https://qiita-image-store.s3.amazonaws.com/0/105865/173a2485-0312-f3fc-e585-7d20f7e64863.png">

基本は pubnub://pubsub:channel?options で、optionsにkeyが3種類設定されていれば使えそうです。

## 実行コードを書く

以下のコードサンプルでは、
送信側では一秒ごとにメッセージ"foo"をPubNubにポストします。
受信側ではPubNubから受信したメッセージを標準出力しています。

```java:App.java
package com.mycode.myiot;

import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.main.Main;

public class App {
    public static void main(String[] args) throws Exception{
        Main main = new Main();
        main.addRouteBuilder(new RouteBuilder(){
            @Override
            public void configure() throws Exception { // ここまでApache Camelの基本共通コード

                String pubKey = "ゆ○式"; // 有効な値を設定されたし
                String subKey = "一般"; // 有効な値を設定されたし
                String secKey = "完売"; // 有効な値を設定されたし
                String pubnubEndpointUri = String.format("pubnub://pubsub:channel?publisherKey=%s&subscriberKey=%s&secretKey=%s", pubKey,subKey,secKey);
                
                // 送信側のルール定義
                from("timer:foo") // 1秒ごとに実行
                        .setBody(constant("foo")) // 送信内容を文字列"foo"に設定
                        .to(pubnubEndpointUri); // PubNubへ送信

                // 受信側のルール定義
                from(pubnubEndpointUri) // PubNubから受信
                        .to("log:foo"); // 受信内容をログに出力する

            } // ここからApache Camelの基本共通コード
        });
        main.run();
    }
}
```

## 実行結果
<img width="422" alt="無題6.png" src="https://qiita-image-store.s3.amazonaws.com/0/105865/1f80c845-ff57-81be-1bf1-2b2766c4a717.png">

受信側に1秒ごとにfooが流れてきていることがわかります。ただこれだけだといまいちPubNubサーバーを通している感がないので、
ためしに、受信部分をコメントアウトした状態でApp.javaを実行します。その次に今度は送信部分をコメントアウトして、いくつかApp.javaを実行します。これにより簡易的に1対多のPub/Subを作り出します。

その場合でもやはりそれぞれにログが出力されますので、めでたくPubNubサーバーをApache Camelから使うことが出来た、ということのようです。

## 感想

勝手アプリを作成する際に、自前でWebsocketサーバーを立てることはもうなくなったかもなぁ、と思いました。
逆にこれまで「Websocketを使えば何とか実装できるかなぁ」でとどまっていたアイデアは、だいぶ実装しやすくなったと思います。ユーザーを識別するあたりの機能を検証する必要がありますが。

## ごくごく個人的な、感想…
最近はまっているGoogleトレンドのスクリーンショットを載せておきます。（実際のページは画像をクリック）
[<img width="669" alt="無題7.png" src="https://qiita-image-store.s3.amazonaws.com/0/105865/787c7a4a-e099-34ef-118c-43023613eefa.png">](https://www.google.co.jp/trends/explore#q=PubNub%2C%20Apache%20Camel&cmpt=q&tz=Etc%2FGMT-9)

Apache Camelの規模感を知る自分視点では、PubNubもなかなかイケてる規模感のようです。
（Milkcocoaは同名の対象が多いそうなのでやめておきました。）
PubNubもApache Camelも、国内では「知る人ぞ知る」製品だと思います。でもその「比較的知られていない」者の間にすでにコンポーネントが用意されているのですから、海外の器のデカさや先進性を実感させられます。

Milkcocoaの人は、現状だとApache Camelへの対応とか考えてないでしょうし、自分も別に求めていませんが、「PubNubに追いつけ追い越せ」論で行くと、
結局こういう細か～な対応状況で海外の製品とは差がつくのかなぁとも思ってます。
Milkcocoaに限らず国産製品全般の話ですが。どうしたらいいんでしょう。（ふわっとした終わり方）