Bibliothèque client fournissant WAMP sur Java 8 (Netty) et Android, ainsi que WebSocket (sécurisé) pour Android.
Autobahn|Java est un sous-projet du projet Autobahn et fournit des implémentations client open source pour
fonctionnant sur Android et Netty/Java8/JVM.
La couche WebSocket utilise une API utilisateur basée sur le rappel et est spécifiquement écrite pour Android. Par exemple, il n'exécute aucun élément réseau sur le thread principal (UI).
La couche WAMP utilise Java 8 CompletableFuture pour les actions WAMP (appel, enregistrement, publication et abonnement) et le modèle Observer pour les événements du cycle de vie de session, d'abonnement et d'enregistrement WAMP.
La bibliothèque est sous licence MIT, maintenue par le projet Crossbar.io, testée à l'aide d'AutobahnTestsuite et publiée sous forme de JAR sur Maven et d'image de chaîne d'outils Docker sur Dockerhub.
Récupérez via Maven :
< dependency >
< groupId >io.crossbar.autobahn</ groupId >
< artifactId >autobahn-android</ artifactId >
< version >21.7.1</ version >
</ dependency >
Graduation :
dependencies {
implementation ' io.crossbar.autobahn:autobahn-android:21.7.1 '
}
Pour les systèmes non Android, utilisez l'artefactID autobahn-java
ou téléchargez simplement le dernier JAR.
Les clients de démonstration sont faciles à exécuter, il vous suffit d'installer make
et docker
pour faire avancer les choses.
$ make crossbar # Starts crossbar in a docker container
$ make python # Starts a python based WAMP components that provides calls for the Java demo client
et enfin
$ make java # Starts the java (Netty) based demo client that performs WAMP actions
Le code dans la galerie de démonstration contient quelques exemples sur la façon d'utiliser la bibliothèque Autobahn, il contient également des méthodes pratiques à utiliser. Vous trouverez ci-dessous un ensemble d'exemples de code de base montrant les 4 actions WAMP.
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 )));
}
Puisque nous accédons uniquement args
dans onEvent(), nous pourrions le simplifier comme suit :
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 ;
});
}
Un appel plus simple ressemblerait à :
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 ));
}
Un add2
très précis peut ressembler à :
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 ))));
}
Procédure d'appel avec des paramètres de type de données variables
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 ();
}
L'authentification est simple, il suffit de créer un objet de l'authentificateur souhaité et de le transmettre au client
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 ();
}
Vous pouvez également fournir une liste d'authentificateurs
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 prend également en charge les POJO
Voici comment appeler une procédure distante qui renvoie une liste de POJO Personne
// 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 );
Enregistrez également une procédure qui renvoie une personne
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 ));
});
}
Exemple d'écho
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 );
}
});
Construire une autoroute est assez simple
Pour Android, nous vous recommandons d'utiliser Android Studio. Importez simplement le projet dans Android Studio, il vous dira s'il y a des dépendances manquantes, installez-les, puis construisez simplement le projet à partir de Build > Rebuild Project
et vous aurez l'artefact aar dans autobahn/build/outputs/aar/
Pour produire une version pour les systèmes non Android, assurez-vous d'avoir installé Docker et Make, puis utilisez simplement la commande Run Below dans le répertoire racine du projet.
make build_autobahn
et cela affichera le fichier jar dans autobahn/build/libs/
.
Contactez-nous en rejoignant notre forum.
La version 1 de cette bibliothèque est toujours dans le dépôt ici, mais n'est plus maintenue.
La version 1 ne prenait en charge que WebSocket non sécurisé sur Android et ne prenait en charge que WAMP v1.
Ces deux problèmes sont résolus dans la version (actuelle) d'Autobahn|Java.