Akkaの簡単なサンプル(Java)

簡単なAkkaのサンプルプログラムです。メッセージを送信、受信してエコーを返します。

## Step1

### Gradle

```gralde:build.gradle
apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    compile 'com.typesafe.akka:akka-actor_2.11:2.4.7'
}
```

### Client

インスタンス生成はPropsを使用するのが流儀みたいです。
詳細は後日調べて載せます。

```java:Client.java
package com.example;
import akka.actor.*;
import akka.event.Logging;
import akka.event.LoggingAdapter;

/**
 * クライアント
 */
public class Client extends UntypedActor {
    
    /** Server */
    private final ActorRef          server;
    
    /** ロガー */
    private final LoggingAdapter    logger;
    
    /**
     * アクター生成用のPropsを返す
     * 
     * @return  Props
     */
    public static Props props() {
        return Props.create(Client.class);
    }
    
    /**
     * コンストラクタ
     */
    public Client() {
        server = context().system().actorOf(Server.props(), "Server");
        logger = Logging.getLogger(context().system(), this);
        getSelf().tell("Start", getSelf());
    }
    
    /**
     * 受信処理
     */
    @Override
    public void onReceive(Object message) throws Exception {
        logger.info(message.toString());
        if (message instanceof String) {
            if (message.equals("Start")) {
                server.tell("こんにちは", getSelf());
                return;
            }
        }
        // 上記以外は処理しない
        unhandled(message);
    }

    /**
     * エントリーポイント
     * 
     * @param args  コマンドライン引数
     */
    public static void main(String[] args) {
        ActorSystem.create("Apps").actorOf(Client.props(), "Client");
    }
}
```

### Server

```java:Server.java
package com.example;
import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.event.Logging;
import akka.event.LoggingAdapter;

/**
 * サーバ
 */
public class Server extends UntypedActor {
    
    /** ロガー */
    private final LoggingAdapter    logger;
    
    /**
     * アクター生成用のPropsを返す
     * 
     * @return  Props
     */
    public static Props props() {
        return Props.create(Server.class);
    }
    
    /**
     * コンストラクタ
     */
    public Server() {
        logger = Logging.getLogger(context().system(), this);
    }
    
    /**
     * 受信処理
     */
    @Override
    public void onReceive(Object message) throws Exception {
        logger.info(message.toString());
        if (message instanceof String) {
            getSender().tell("Echo " + (String)message, getSelf());
        }
    }
    
}
```

### 実行結果

```log
[INFO] [06/24/2016 14:11:58.689] [Apps-akka.actor.default-dispatcher-2] [akka://Apps/user/Client] Start
[INFO] [06/24/2016 14:11:58.690] [Apps-akka.actor.default-dispatcher-5] [akka://Apps/user/Server] こんにちは
[INFO] [06/24/2016 14:11:58.691] [Apps-akka.actor.default-dispatcher-3] [akka://Apps/user/Client] Echo こんにちは
```

## Step2

schedulerを使用して処理を繰り返すように修正します。
scheduleOnesは1回きりです。scheduleを使用すると繰り返し実行できます。

### Client

```java:Client.java
package com.example;
import java.util.concurrent.TimeUnit;

import akka.actor.*;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import scala.concurrent.duration.Duration;

/**
 * クライアント
 */
public class Client extends UntypedActor {
    
    /** Server */
    private final ActorRef          server;
    
    /** ロガー */
    private final LoggingAdapter    logger;
    
    /**
     * アクター生成用のPropsを返す
     * 
     * @return  Props
     */
    public static Props props() {
        return Props.create(Client.class);
    }
    
    /**
     * コンストラクタ
     */
    public Client() {
        server = context().system().actorOf(Server.props(), "Server");
        logger = Logging.getLogger(context().system(), this);
        getSelf().tell("Start", getSelf());
    }
    
    /**
     * 受信処理
     */
    @Override
    public void onReceive(Object message) throws Exception {
        logger.info(message.toString());
        if (message instanceof String) {
            if (message.equals("Start")) {
                server.tell("こんにちは", getSelf());
                nextShedule(); 
                return;
            }
        }
        unhandled(message);
    }
    
    /**
     * 次処理をスケジューリングする
     */
    private void nextShedule() {
        context().system().scheduler().scheduleOnce(
                Duration.create(5, TimeUnit.SECONDS),   // delay
                getSelf(),                              // receiver
                "Start",                                // message
                context().dispatcher(),                 // executor
                getSelf()                               //sender
                );
    }

    /**
     * エントリーポイント
     * 
     * @param args  コマンドライン引数
     */
    public static void main(String[] args) {
        ActorSystem.create("Apps").actorOf(Client.props(), "Client");
    }
}
```

### 実行結果

```log
[INFO] [06/24/2016 15:25:12.290] [Apps-akka.actor.default-dispatcher-3] [akka://Apps/user/Client] Start
[INFO] [06/24/2016 15:25:12.293] [Apps-akka.actor.default-dispatcher-4] [akka://Apps/user/Server] こんにちは
[INFO] [06/24/2016 15:25:12.293] [Apps-akka.actor.default-dispatcher-3] [akka://Apps/user/Client] Echo こんにちは
[INFO] [06/24/2016 15:25:17.312] [Apps-akka.actor.default-dispatcher-7] [akka://Apps/user/Client] Start
[INFO] [06/24/2016 15:25:17.313] [Apps-akka.actor.default-dispatcher-3] [akka://Apps/user/Server] こんにちは
[INFO] [06/24/2016 15:25:17.313] [Apps-akka.actor.default-dispatcher-7] [akka://Apps/user/Client] Echo こんにちは
[INFO] [06/24/2016 15:25:22.334] [Apps-akka.actor.default-dispatcher-2] [akka://Apps/user/Client] Start
[INFO] [06/24/2016 15:25:22.334] [Apps-akka.actor.default-dispatcher-7] [akka://Apps/user/Server] こんにちは
[INFO] [06/24/2016 15:25:22.334] [Apps-akka.actor.default-dispatcher-2] [akka://Apps/user/Client] Echo こんにちは
```

停止する処理を入れていないので延々処理されます。