BAEL-1724 Akka HTTP Initial Commit
This commit is contained in:
parent
01b9b5673e
commit
8696022889
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0"?>
|
||||
<project
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>akka-http</artifactId>
|
||||
<name>akka-http</name>
|
||||
|
||||
<parent>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-http_2.12</artifactId>
|
||||
<version>${akka.http.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-stream_2.12</artifactId>
|
||||
<version>${akka.stream.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-http-jackson_2.12</artifactId>
|
||||
<version>${akka.http.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-http-testkit_2.12</artifactId>
|
||||
<version>${akka.http.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<akka.http.version>10.0.11</akka.http.version>
|
||||
<akka.stream.version>2.5.11</akka.stream.version>
|
||||
</properties>
|
||||
</project>
|
|
@ -0,0 +1,39 @@
|
|||
package com.baeldung.akkahttp;
|
||||
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
import akka.NotUsed;
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.http.javadsl.ConnectHttp;
|
||||
import akka.http.javadsl.Http;
|
||||
import akka.http.javadsl.ServerBinding;
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.HttpResponse;
|
||||
import akka.http.javadsl.server.AllDirectives;
|
||||
import akka.stream.ActorMaterializer;
|
||||
import akka.stream.javadsl.Flow;
|
||||
|
||||
public class AkkaHttpServer extends AllDirectives {
|
||||
|
||||
private final UserRoutes userRoutes;
|
||||
|
||||
public AkkaHttpServer(ActorSystem system, ActorRef userRegistryActor) {
|
||||
userRoutes = new UserRoutes(system, userRegistryActor);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ActorSystem system = ActorSystem.create("helloAkkaHttpServer");
|
||||
final ActorMaterializer materializer = ActorMaterializer.create(system);
|
||||
|
||||
ActorRef userActorRef = system.actorOf(UserActor.props(), "userActor");
|
||||
|
||||
AkkaHttpServer app = new AkkaHttpServer(system, userActorRef);
|
||||
|
||||
final Flow<HttpRequest, HttpResponse, NotUsed> routeFlow = app.userRoutes.routes().flow(system, materializer);
|
||||
|
||||
final CompletionStage<ServerBinding> binding = Http.get(system).bindAndHandle(routeFlow,
|
||||
ConnectHttp.toHost("localhost", 8080), materializer);
|
||||
|
||||
System.out.println("Server is online at http://localhost:8080/");
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.baeldung.akkahttp;
|
||||
|
||||
/**
|
||||
* User Entity
|
||||
*
|
||||
*/
|
||||
public class User {
|
||||
|
||||
private final String name;
|
||||
private final String address;
|
||||
|
||||
public User() {
|
||||
this.name = "";
|
||||
this.address = "";
|
||||
}
|
||||
|
||||
public User(String name, String address) {
|
||||
this.name = name;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package com.baeldung.akkahttp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.actor.Props;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
|
||||
/**
|
||||
* User Actor
|
||||
*
|
||||
*/
|
||||
public class UserActor extends AbstractActor {
|
||||
|
||||
LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
|
||||
/**
|
||||
* In memory List to hold the users added via POST operation.
|
||||
*/
|
||||
private final List<User> users = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* To define UserActor Props.
|
||||
*
|
||||
* @return Props
|
||||
*/
|
||||
static Props props() {
|
||||
return Props.create(UserActor.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* createReveive() implementation
|
||||
*/
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder().match(UserRegistryMessages.GetUsers.class, getUsers -> getSender().tell(new Users(users), getSelf()))
|
||||
.match(UserRegistryMessages.CreateUser.class, createUser -> {
|
||||
users.add(createUser.getUser());
|
||||
getSender().tell(new UserRegistryMessages.ActionPerformed(String.format("User %s created.", createUser.getUser()
|
||||
.getName())), getSelf());
|
||||
})
|
||||
.match(UserRegistryMessages.GetUser.class, getUser -> {
|
||||
getSender().tell(users.stream()
|
||||
.filter(user -> user.getName()
|
||||
.equals(getUser.getName()))
|
||||
.findFirst(), getSelf());
|
||||
})
|
||||
.match(UserRegistryMessages.DeleteUser.class, deleteUser -> {
|
||||
users.removeIf(user -> user.getName()
|
||||
.equals(deleteUser.getName()));
|
||||
getSender().tell(new UserRegistryMessages.ActionPerformed(String.format("User %s deleted.", deleteUser.getName())), getSelf());
|
||||
|
||||
})
|
||||
.matchAny(o -> log.info("received unknown message"))
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package com.baeldung.akkahttp;
|
||||
|
||||
/**
|
||||
* Defines all messages related to User Actor
|
||||
*
|
||||
*/
|
||||
public interface UserRegistryMessages {
|
||||
|
||||
class GetUsers implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
|
||||
class ActionPerformed implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String description;
|
||||
|
||||
public ActionPerformed(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
|
||||
class CreateUser implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final User user;
|
||||
|
||||
public CreateUser(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
class GetUser implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final String name;
|
||||
|
||||
public GetUser(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
class DeleteUser implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final String name;
|
||||
|
||||
public DeleteUser(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package com.baeldung.akkahttp;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
import akka.http.javadsl.marshallers.jackson.Jackson;
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
import akka.http.javadsl.server.AllDirectives;
|
||||
import akka.http.javadsl.server.PathMatchers;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.pattern.PatternsCS;
|
||||
import akka.util.Timeout;
|
||||
|
||||
public class UserRoutes extends AllDirectives {
|
||||
|
||||
private final ActorRef userActorRef;
|
||||
private final LoggingAdapter log;
|
||||
Timeout timeout = new Timeout(Duration.create(5, TimeUnit.SECONDS));
|
||||
|
||||
public UserRoutes(ActorSystem system, ActorRef userActorRef) {
|
||||
this.userActorRef = userActorRef;
|
||||
log = Logging.getLogger(system, this);
|
||||
}
|
||||
|
||||
public Route routes() {
|
||||
return pathPrefix("users", () -> route(getOrPostUsers(), path(PathMatchers.segment(), name -> route(getUser(name), deleteUser(name)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines and returns a route to get the user by name
|
||||
*
|
||||
* @param name
|
||||
* @return Route
|
||||
*/
|
||||
private Route getUser(String name) {
|
||||
|
||||
Route getRoute = get(() -> {
|
||||
CompletionStage<Optional<User>> user = PatternsCS.ask(userActorRef, new UserRegistryMessages.GetUser(name), timeout)
|
||||
.thenApply(obj -> (Optional<User>) obj);
|
||||
|
||||
return onSuccess(() -> user, performed -> {
|
||||
if (performed.isPresent())
|
||||
return complete(StatusCodes.OK, performed.get(), Jackson.marshaller());
|
||||
else
|
||||
return complete(StatusCodes.NOT_FOUND);
|
||||
});
|
||||
});
|
||||
return getRoute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines and returns a Route to delete the user by name.
|
||||
*
|
||||
* @param name
|
||||
* @return Route
|
||||
*/
|
||||
private Route deleteUser(String name) {
|
||||
|
||||
Route deleteRoute = delete(() -> {
|
||||
CompletionStage<ActionPerformed> userDeleted = PatternsCS.ask(userActorRef, new UserRegistryMessages.DeleteUser(name), timeout)
|
||||
.thenApply(obj -> (ActionPerformed) obj);
|
||||
|
||||
return onSuccess(() -> userDeleted, performed -> {
|
||||
log.info("Deleted user [{}]: {}", name, performed.getDescription());
|
||||
return complete(StatusCodes.OK, performed, Jackson.marshaller());
|
||||
});
|
||||
});
|
||||
|
||||
return deleteRoute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines two routes, one to get all users and the other is to post users.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Route getOrPostUsers() {
|
||||
return pathEnd(() -> route(get(() -> {
|
||||
CompletionStage<Users> futureUsers = PatternsCS.ask(userActorRef, new UserRegistryMessages.GetUsers(), timeout)
|
||||
.thenApply(obj -> (Users) obj);
|
||||
return onSuccess(() -> futureUsers, users -> complete(StatusCodes.OK, users, Jackson.marshaller()));
|
||||
}), post(() -> entity(Jackson.unmarshaller(User.class), user -> {
|
||||
CompletionStage<ActionPerformed> userCreated = PatternsCS.ask(userActorRef, new CreateUser(user), timeout)
|
||||
.thenApply(obj -> (ActionPerformed) obj);
|
||||
return onSuccess(() -> userCreated, performed -> {
|
||||
log.info("Created user [{}]: {}", user.getName(), performed.getDescription());
|
||||
return complete(StatusCodes.CREATED, performed, Jackson.marshaller());
|
||||
});
|
||||
}))));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.baeldung.akkahttp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class is used to send the response enclosed by Users.
|
||||
*
|
||||
*/
|
||||
public class Users {
|
||||
|
||||
private final List<User> users;
|
||||
|
||||
public Users() {
|
||||
this.users = new ArrayList<>();
|
||||
}
|
||||
|
||||
public Users(List<User> users) {
|
||||
this.users = users;
|
||||
}
|
||||
|
||||
public List<User> getUsers() {
|
||||
return users;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue