Akka vo svojej dokonalosti aktorového frameworku môže poslúžiť aj ako nástroj pre vzdialené volanie procedúr.
Aha, príklad otáčača reťazcov.
Potrebujeme:
akka-actor_2.10-2.2.3.jar
scala-library.jar
(verzie 2.10)protobuf-java-2.4.1.jar
config-1.0.2.jar
akka-remote_2.10-2.2.3.jar
netty-3.6.6.Final.jar
Posledné dva JARy potrebujeme kvôli remotingu.
Server
Aktor
Aktor pre otáčanie prijme jeden reťazec a vráti odosielateľovi otočený reťazec.
package sk.upjs.ics.novotnyr.akka;
import akka.actor.UntypedActor;
public class StringReversingActor extends UntypedActor {
@Override
public void onReceive(Object message) throws Exception {
if(message instanceof String) {
String inputString = (String) message;
String result = reverse(inputString);
sender().tell(result, getSelf());
} else {
unhandled(message);
}
}
private String reverse(String string) {
return new StringBuilder(string).reverse().toString();
}
}
Reťazce nie sú ideálne typy pre správy (Akka odrádza od používania základných typov), ale pre jednoduchosť budú stačiť. Dôležité je, že sú nemenné (immutable) a serializovateľné (implementujú java.io.Serializable
).
Konfigurácia
package sk.upjs.ics.novotnyr.akka;
import akka.actor.ActorSystem;
import akka.actor.Props;
import com.typesafe.config.ConfigFactory;
public class Server {
public static void main(String[] args) throws Exception {
ActorSystem system = ActorSystem.create("StringReversingSystem", ConfigFactory.load("server.conf"));
system.actorOf(Props.create(StringReversingActor.class), "StringReverse");
}
}
Vytvoríme systém s názvom StringReversingSystem
a vytvoríme v ňom aktora s logickým menom StringReverse
: tie sa totiž objavia vo výslednej URL koncového bodu.
Konfiguráciu načítame zo súboru server.conf
akka {
actor {
provider = "akka.remote.RemoteActorRefProvider"
}
remote {
netty.tcp {
hostname = "127.0.0.1"
port = 2553
}
}
}
- V konfigurácii zapneme poskytovateľa pre volanie vzdialených aktorov.
- Nastavíme hostiteľa, na ktorom pobežíme (buď IPčkou alebo názvom servera)
- Nastavíme port. Defaultne 2552, ale predefinujeme ho, aby sme sa nezrazili s portom pre klienta.
- Remoting pobeží na asynchrónnej knižnici Netty nad TCP protokolom.
Celá konfigurácia zverejní aktora na adrese:
akka.tcp://StringReversingSystem@127.0.0.1:2553/user/StringReverse
Klient
Najprv si dajme konfiguráciu
Súbor client.conf
:
akka {
actor {
provider = "akka.remote.RemoteActorRefProvider"
}
}
Žiadna zložitosť, len zapneme podporu pre vzdialených aktorov.
Aj keď pozor: štandardne sa aktorový systém klienta tiež spustí na konkrétnom porte: v tomto prípade na štandardom 2552. To je dôvod, prečo sme na serveri zvolili iný port než na klientovi: pre lokálne spúšťaný server aj klient by sme inak uvideli BindException
indikujúci, že máme pokus o spustenie dvoch služieb na jednom porte.
Java kód
package sk.upjs.ics.novotnyr.akka;
import scala.concurrent.Future;
import akka.actor.ActorRef;
import akka.actor.ActorSelection;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.dispatch.OnSuccess;
import akka.pattern.Patterns;
import com.typesafe.config.ConfigFactory;
public class Client {
public static void main(String[] args) {
ActorSystem actorSystem = ActorSystem.create("client", ConfigFactory.load("client.conf"));
ActorSelection calculator = actorSystem.actorSelection("akka.tcp://StringReversingSystem@158.197.31.121:2553/user/StringReverse");
Duration duration = Duration.create(2, TimeUnit.SECONDS);
Future<Object> future = Patterns.ask(calculator, "mor dni lape je palindrom", duration.toMillis());
Object result = Await.result(future, duration);
System.out.println(result);
actorSystem.shutdown();
}
}
- Vytvoríme ďalší aktorový systém pre klienta podľa konfiguráku
client.conf
. - Vytiahneme vzdialeného aktora cez
actorSelection
, kde za identifikátor použijeme celú URL adresu.- V starých Akkách sa používala metóda
actorFor()
, ktorá síce nerobila na povrchu rozdiel medzi lokálnym a vzdialeným aktorom, ale správala sa odlišne a vracala odlišné hodnoty. Podrobnosti viď dokumentácia.
- V starých Akkách sa používala metóda
- Vytvoríme dvojsekundové obdobie použité pre dve veci:
- čakanie na odpoveď od vzdialeného aktora (pattern ask)
- a na získanie výsledku z
Future
, ktorý bude obsahovať výsledok
- Pri čakaní na výsledok využívame blokovanie, čo je v Akke veľmi zlé, ale keďže ide o demonštračný spúšťač, je to odpustiteľné. (Čakáme totiž na výsledok jednorazovej operácie, po ktorej celá aplikácia skončí.)
To je všetko!