Client-Bibliothek, die WAMP auf Java 8 (Netty) und Android sowie (sicheres) WebSocket für Android bereitstellt.
Autobahn|Java ist ein Teilprojekt des Autobahn-Projekts und stellt Open-Source-Client-Implementierungen für bereit
läuft auf Android und Netty/Java8/JVM.
Die WebSocket-Schicht verwendet eine Callback-basierte Benutzer-API und ist speziell für Android geschrieben. Beispielsweise werden im Hauptthread (UI-Thread) keine Netzwerkfunktionen ausgeführt.
Die WAMP-Schicht verwendet Java 8 CompletableFuture für WAMP-Aktionen (Aufrufen, Registrieren, Veröffentlichen und Abonnieren) und das Observer-Muster für WAMP-Sitzungs-, Abonnement- und Registrierungslebenszyklusereignisse.
Die Bibliothek ist MIT-lizenziert, wird vom Crossbar.io-Projekt verwaltet, mit der AutobahnTestsuite getestet und als JAR für Maven und als Docker-Toolchain-Image für Dockerhub veröffentlicht.
Schnappen Sie sich über Maven:
< dependency >
< groupId >io.crossbar.autobahn</ groupId >
< artifactId >autobahn-android</ artifactId >
< version >21.7.1</ version >
</ dependency >
Gradle:
dependencies {
implementation ' io.crossbar.autobahn:autobahn-android:21.7.1 '
}
Für Nicht-Android-Systeme verwenden Sie die Artefakt-ID autobahn-java
oder laden Sie einfach die neueste JAR-Datei herunter
Die Demo-Clients sind einfach auszuführen, Sie müssen lediglich make
und docker
installieren, um loszulegen.
$ make crossbar # Starts crossbar in a docker container
$ make python # Starts a python based WAMP components that provides calls for the Java demo client
und schließlich
$ make java # Starts the java (Netty) based demo client that performs WAMP actions
Der Code in der Demo-Galerie enthält einige Beispiele zur Verwendung der Autobahnbibliothek sowie praktische Methoden zur Verwendung. Nachfolgend finden Sie eine Reihe grundlegender Codebeispiele, die alle vier WAMP-Aktionen zeigen.
public void demonstrateSubscribe ( Session session , SessionDetails details ) {
// Subscribe to topic to receive its events.
CompletableFuture < Subscription > subFuture = session . subscribe ( "com.myapp.hello" ,
this :: onEvent );
subFuture . whenComplete (( subscription , throwable ) -> {
if ( throwable == null ) {
// We have successfully subscribed.
System . out . println ( "Subscribed to topic " + subscription . topic );
} else {
// Something went bad.
throwable . printStackTrace ();
}
});
}
private void onEvent ( List < Object > args , Map < String , Object > kwargs , EventDetails details ) {
System . out . println ( String . format ( "Got event: %s" , args . get ( 0 )));
}
Da wir in onEvent() nur auf args
zugreifen, könnten wir es wie folgt vereinfachen:
private void onEvent ( List < Object > args ) {
System . out . println ( String . format ( "Got event: %s" , args . get ( 0 )));
}
public void demonstratePublish ( Session session , SessionDetails details ) {
// Publish to a topic that takes a single arguments
List < Object > args = Arrays . asList ( "Hello World!" , 900 , "UNIQUE" );
CompletableFuture < Publication > pubFuture = session . publish ( "com.myapp.hello" , args );
pubFuture . thenAccept ( publication -> System . out . println ( "Published successfully" ));
// Shows we can separate out exception handling
pubFuture . exceptionally ( throwable -> {
throwable . printStackTrace ();
return null ;
});
}
Ein einfacherer Aufruf würde so aussehen:
public void demonstratePublish ( Session session , SessionDetails details ) {
CompletableFuture < Publication > pubFuture = session . publish ( "com.myapp.hello" , "Hi!" );
...
}
public void demonstrateRegister ( Session session , SessionDetails details ) {
// Register a procedure.
CompletableFuture < Registration > regFuture = session . register ( "com.myapp.add2" , this :: add2 );
regFuture . thenAccept ( registration ->
System . out . println ( "Successfully registered procedure: " + registration . procedure ));
}
private CompletableFuture < InvocationResult > add2 (
List < Object > args , Map < String , Object > kwargs , InvocationDetails details ) {
int res = ( int ) args . get ( 0 ) + ( int ) args . get ( 1 );
List < Object > arr = new ArrayList <>();
arr . add ( res );
return CompletableFuture . completedFuture ( new InvocationResult ( arr ));
}
Ein sehr präzises add2
könnte wie folgt aussehen:
private List < Object > add2 ( List < Integer > args , InvocationDetails details ) {
int res = args . get ( 0 ) + args . get ( 1 );
return Arrays . asList ( res , details . session . getID (), "Java" );
}
public void demonstrateCall ( Session session , SessionDetails details ) {
// Call a remote procedure.
CompletableFuture < CallResult > callFuture = session . call ( "com.myapp.add2" , 10 , 20 );
callFuture . thenAccept ( callResult ->
System . out . println ( String . format ( "Call result: %s" , callResult . results . get ( 0 ))));
}
Aufrufprozedur mit variablen Datentypparametern
public void demonstrateCall ( Session session , SessionDetails details ) {
// Call a remote procedure.
byte [] var1 = new byte [ 20 ];
String var2 = "A sample text" ;
int var3 = 99 ;
List < Object > args = new ArrayList <>();
args . add ( var1 );
args . add ( var2 );
args . add ( var3 );
CompletableFuture < CallResult > callFuture = session . call ( "com.myapp.myproc" , args );
callFuture . thenAccept ( callResult ->
System . out . println ( String . format ( "Call result: %s" , callResult . results . get ( 0 ))));
}
public void main () {
// Create a session object
Session session = new Session ();
// Add all onJoin listeners
session . addOnJoinListener ( this :: demonstrateSubscribe );
session . addOnJoinListener ( this :: demonstratePublish );
session . addOnJoinListener ( this :: demonstrateCall );
session . addOnJoinListener ( this :: demonstrateRegister );
// finally, provide everything to a Client and connect
Client client = new Client ( session , url , realm );
CompletableFuture < ExitInfo > exitInfoCompletableFuture = client . connect ();
}
Die Authentifizierung ist einfach. Wir müssen lediglich ein Objekt des gewünschten Authentifikators erstellen und dieses an den Client übergeben
public void main () {
...
IAuthenticator authenticator = new TicketAuth ( authid , ticket );
Client client = new Client ( session , url , realm , authenticator );
CompletableFuture < ExitInfo > exitInfoCompletableFuture = client . connect ();
}
public void main () {
...
IAuthenticator authenticator = new ChallengeResponseAuth ( authid , secret );
Client client = new Client ( session , url , realm , authenticator );
CompletableFuture < ExitInfo > exitInfoCompletableFuture = client . connect ();
}
public void main () {
...
IAuthenticator authenticator = new CryptosignAuth ( authid , privkey , pubkey );
Client client = new Client ( session , url , realm , authenticator );
CompletableFuture < ExitInfo > exitInfoCompletableFuture = client . connect ();
}
Sie können auch eine Liste von Authentifikatoren bereitstellen
public void main () {
...
List < IAuthenticator > authenticators = new ArrayList <>();
authenticators . add ( new TicketAuth ( authid , ticket ));
authenticators . add ( new CryptosignAuth ( authid , privkey , pubkey ));
Client client = new Client ( session , url , realm , authenticators );
CompletableFuture < ExitInfo > exitInfoCompletableFuture = client . connect ();
}
Autobahn unterstützt auch POJOs
So rufen Sie eine Remote-Prozedur auf, die eine Liste von Personen-POJOs zurückgibt
// Call a remote procedure that returns a Person with id 1
CompletableFuture < Person > callFuture = mSession . call ( "com.example.get_person" , 1 );
callFuture . whenCompleteAsync (( person , throwable ) -> {
if ( throwable != null ) {
// handle error
} else {
// success!
// do something with person
}
}, mExecutor );
// call a remote procedure that returns a List<Person>
CompletableFuture < List < Person >> callFuture = mSession . call (
// remote procedure to call
"com.example.get_persons_by_department" ,
// positional call arguments
new ArrayList < Object >() { List . of ( "department-7" )},
// call return type
new TypeReference < List < Person >>() {}
);
callFuture . whenCompleteAsync (( persons , throwable ) -> {
if ( throwable != null ) {
// handle error
} else {
// success!
for ( Person person : persons ) {
// do something with person
}
}
}, mExecutor );
Registrieren Sie auch eine Prozedur, die eine Person zurückgibt
private Person get_person () {
return new Person ( "john" , "doe" , "hr" );
}
private void main () {
CompletableFuture < Registration > regFuture = session . register (
"io.crossbar.example.get_person" , this :: get_person );
regFuture . whenComplete (( registration , throwable ) -> {
System . out . println ( String . format (
"Registered procedure %s" , registration . procedure ));
});
}
Echo-Beispiel
WebSocketConnection connection = new WebSocketConnection ();
connection . connect ( "wss://echo.websocket.org" , new WebSocketConnectionHandler () {
@ Override
public void onConnect ( ConnectionResponse response ) {
System . out . println ( "Connected to server" );
}
@ Override
public void onOpen () {
connection . sendMessage ( "Echo with Autobahn" );
}
@ Override
public void onClose ( int code , String reason ) {
System . out . println ( "Connection closed" );
}
@ Override
public void onMessage ( String payload ) {
System . out . println ( "Received message: " + payload );
connection . sendMessage ( payload );
}
});
Der Bau einer Autobahn ist ziemlich einfach
Für Android empfehlen wir die Verwendung von Android Studio. Importieren Sie einfach das Projekt in Android Studio. Dort erfahren Sie, ob Abhängigkeiten fehlen. Installieren Sie diese und erstellen Sie dann einfach das Projekt über Build > Rebuild Project
und Sie erhalten das AAR-Artefakt in autobahn/build/outputs/aar/
Um einen Build für Nicht-Android-Systeme zu erstellen, stellen Sie sicher, dass Docker und Make installiert sind, und verwenden Sie dann einfach den folgenden Befehl im Stammverzeichnis des Projekts
make build_autobahn
und das gibt die JAR-Datei in autobahn/build/libs/
aus.
Nehmen Sie Kontakt mit uns auf, indem Sie unserem Forum beitreten.
Version 1 dieser Bibliothek befindet sich hier noch im Repo, wird aber nicht mehr gepflegt.
Version 1 unterstützte nur nicht sicheres WebSocket auf Android und nur WAMP v1.
Beide Probleme sind in der (aktuellen) Version von Autobahn|Java behoben.