Java 11501 (#12405)

* added parent module (akka-modules)

* moved akka-http(submodule) to akka-modules(parent)

* moved akka-streams(submodule) to akka-modules(parent)

* moved spring-akka(submodule) to akka-modules(parent)

* deleted submodules that we moved to akka-modules

Co-authored-by: panagiotiskakos <panagiotis.kakos@libra-is.com>
This commit is contained in:
panos-kakos
2022-06-24 17:56:57 +01:00
committed by GitHub
parent 2975abc810
commit 31bd634134
26 changed files with 42 additions and 9 deletions

3
akka-modules/README.md Normal file
View File

@@ -0,0 +1,3 @@
## Akka
This module contains modules about Akka.

View File

@@ -0,0 +1,7 @@
## Akka HTTP
This module contains articles about Akka HTTP.
### Relevant articles:
- [Introduction to Akka HTTP](https://www.baeldung.com/akka-http)

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>akka-http</artifactId>
<name>akka-http</name>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>akka-modules</artifactId>
<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>
<akka.http.version>10.0.11</akka.http.version>
<akka.stream.version>2.5.11</akka.stream.version>
</properties>
</project>

View File

@@ -0,0 +1,26 @@
package com.baeldung.akkahttp;
public class User {
private final Long id;
private final String name;
public User() {
this.name = "";
this.id = null;
}
public User(Long id, String name) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public Long getId() {
return id;
}
}

View File

@@ -0,0 +1,41 @@
package com.baeldung.akkahttp;
import akka.actor.AbstractActor;
import akka.actor.Props;
import akka.japi.pf.FI;
import com.baeldung.akkahttp.UserMessages.ActionPerformed;
import com.baeldung.akkahttp.UserMessages.CreateUserMessage;
import com.baeldung.akkahttp.UserMessages.GetUserMessage;
class UserActor extends AbstractActor {
private UserService userService = new UserService();
static Props props() {
return Props.create(UserActor.class);
}
@Override
public Receive createReceive() {
return receiveBuilder()
.match(CreateUserMessage.class, handleCreateUser())
.match(GetUserMessage.class, handleGetUser())
.build();
}
private FI.UnitApply<CreateUserMessage> handleCreateUser() {
return createUserMessageMessage -> {
userService.createUser(createUserMessageMessage.getUser());
sender().tell(new ActionPerformed(String.format("User %s created.", createUserMessageMessage.getUser()
.getName())), getSelf());
};
}
private FI.UnitApply<GetUserMessage> handleGetUser() {
return getUserMessageMessage -> {
sender().tell(userService.getUser(getUserMessageMessage.getUserId()), getSelf());
};
}
}

View File

@@ -0,0 +1,49 @@
package com.baeldung.akkahttp;
import java.io.Serializable;
public interface UserMessages {
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 CreateUserMessage implements Serializable {
private static final long serialVersionUID = 1L;
private final User user;
public CreateUserMessage(User user) {
this.user = user;
}
public User getUser() {
return user;
}
}
class GetUserMessage implements Serializable {
private static final long serialVersionUID = 1L;
private final Long userId;
public GetUserMessage(Long userId) {
this.userId = userId;
}
public Long getUserId() {
return userId;
}
}
}

View File

@@ -0,0 +1,70 @@
package com.baeldung.akkahttp;
import java.util.Optional;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.http.javadsl.marshallers.jackson.Jackson;
import akka.http.javadsl.model.StatusCodes;
import akka.http.javadsl.server.HttpApp;
import akka.http.javadsl.server.Route;
import akka.pattern.PatternsCS;
import akka.util.Timeout;
import com.baeldung.akkahttp.UserMessages.ActionPerformed;
import com.baeldung.akkahttp.UserMessages.CreateUserMessage;
import com.baeldung.akkahttp.UserMessages.GetUserMessage;
import scala.concurrent.duration.Duration;
import static akka.http.javadsl.server.PathMatchers.*;
class UserServer extends HttpApp {
private final ActorRef userActor;
Timeout timeout = new Timeout(Duration.create(5, TimeUnit.SECONDS));
UserServer(ActorRef userActor) {
this.userActor = userActor;
}
@Override
public Route routes() {
return path("users", this::postUser)
.orElse(path(segment("users").slash(longSegment()), id ->
route(getUser(id))));
}
private Route getUser(Long id) {
return get(() -> {
CompletionStage<Optional<User>> user = PatternsCS.ask(userActor, new GetUserMessage(id), 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);
});
});
}
private Route postUser() {
return route(post(() -> entity(Jackson.unmarshaller(User.class), user -> {
CompletionStage<ActionPerformed> userCreated = PatternsCS.ask(userActor, new CreateUserMessage(user), timeout)
.thenApply(obj -> (ActionPerformed) obj);
return onSuccess(() -> userCreated, performed -> {
return complete(StatusCodes.CREATED, performed, Jackson.marshaller());
});
})));
}
public static void main(String[] args) throws Exception {
ActorSystem system = ActorSystem.create("userServer");
ActorRef userActor = system.actorOf(UserActor.props(), "userActor");
UserServer server = new UserServer(userActor);
server.startServer("localhost", 8080, system);
}
}

View File

@@ -0,0 +1,35 @@
package com.baeldung.akkahttp;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class UserService {
private final static List<User> users = new ArrayList<>();
static {
users.add(new User(1l, "Alice"));
users.add(new User(2l, "Bob"));
users.add(new User(3l, "Chris"));
users.add(new User(4l, "Dick"));
users.add(new User(5l, "Eve"));
users.add(new User(6l, "Finn"));
}
public Optional<User> getUser(Long id) {
return users.stream()
.filter(user -> user.getId()
.equals(id))
.findFirst();
}
public void createUser(User user) {
users.add(user);
}
public List<User> getUsers(){
return users;
}
}

View File

@@ -0,0 +1,53 @@
package com.baeldung.akkahttp;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.http.javadsl.model.ContentTypes;
import akka.http.javadsl.model.HttpEntities;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.testkit.JUnitRouteTest;
import akka.http.javadsl.testkit.TestRoute;
import org.junit.Ignore;
import org.junit.Test;
public class UserServerUnitTest extends JUnitRouteTest {
ActorSystem system = ActorSystem.create("helloAkkaHttpServer");
ActorRef userActorRef = system.actorOf(UserActor.props(), "userActor");
TestRoute appRoute = testRoute(new UserServer(userActorRef).routes());
@Ignore
@Test
public void whenRequest_thenActorResponds() {
appRoute.run(HttpRequest.GET("/users/1"))
.assertEntity(alice())
.assertStatusCode(200);
appRoute.run(HttpRequest.GET("/users/42"))
.assertStatusCode(404);
appRoute.run(HttpRequest.DELETE("/users/1"))
.assertStatusCode(405);
appRoute.run(HttpRequest.DELETE("/users/42"))
.assertStatusCode(405);
appRoute.run(HttpRequest.POST("/users")
.withEntity(HttpEntities.create(ContentTypes.APPLICATION_JSON, zaphod())))
.assertStatusCode(201);
}
private String alice() {
return "{\"id\":1,\"name\":\"Alice\"}";
}
private String zaphod() {
return "{\"id\":42,\"name\":\"Zaphod\"}";
}
}

View File

@@ -0,0 +1,7 @@
## Akka Streams
This module contains articles about Akka Streams.
### Relevant articles
- [Guide to Akka Streams](https://www.baeldung.com/akka-streams)

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>akka-streams</artifactId>
<name>akka-streams</name>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>akka-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-stream_${scala.version}</artifactId>
<version>${akkastreams.version}</version>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-stream-testkit_${scala.version}</artifactId>
<version>${akkastreams.version}</version>
</dependency>
</dependencies>
<properties>
<akkastreams.version>2.5.2</akkastreams.version>
<scala.version>2.11</scala.version>
</properties>
</project>

View File

@@ -0,0 +1,14 @@
package com.baeldung.akkastreams;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
public class AverageRepository {
CompletionStage<Double> save(Double average) {
return CompletableFuture.supplyAsync(() -> {
System.out.println("saving average: " + average);
return average;
});
}
}

View File

@@ -0,0 +1,74 @@
package com.baeldung.akkastreams;
import akka.Done;
import akka.NotUsed;
import akka.actor.ActorSystem;
import akka.stream.ActorMaterializer;
import akka.stream.javadsl.Flow;
import akka.stream.javadsl.Keep;
import akka.stream.javadsl.Sink;
import akka.stream.javadsl.Source;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.stream.Collectors;
public class DataImporter {
private final ActorSystem actorSystem;
private final AverageRepository averageRepository = new AverageRepository();
public DataImporter(ActorSystem actorSystem) {
this.actorSystem = actorSystem;
}
private List<Integer> parseLine(String line) {
String[] fields = line.split(";");
return Arrays.stream(fields)
.map(Integer::parseInt)
.collect(Collectors.toList());
}
private Flow<String, Integer, NotUsed> parseContent() {
return Flow.of(String.class).mapConcat(this::parseLine);
}
private Flow<Integer, Double, NotUsed> computeAverage() {
return Flow.of(Integer.class).grouped(2).mapAsyncUnordered(8, integers ->
CompletableFuture.supplyAsync(() -> integers
.stream()
.mapToDouble(v -> v)
.average()
.orElse(-1.0)));
}
Flow<String, Double, NotUsed> calculateAverage() {
return Flow.of(String.class)
.via(parseContent())
.via(computeAverage());
}
private Sink<Double, CompletionStage<Done>> storeAverages() {
return Flow.of(Double.class)
.mapAsyncUnordered(4, averageRepository::save)
.toMat(Sink.ignore(), Keep.right());
}
CompletionStage<Done> calculateAverageForContent(String content) {
return Source.single(content)
.via(calculateAverage())
.runWith(storeAverages(), ActorMaterializer.create(actorSystem))
.whenComplete((d, e) -> {
if (d != null) {
System.out.println("Import finished ");
} else {
e.printStackTrace();
}
});
}
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@@ -0,0 +1,43 @@
package com.baeldung.akkastreams;
import akka.NotUsed;
import akka.actor.ActorSystem;
import akka.stream.ActorMaterializer;
import akka.stream.javadsl.Flow;
import akka.stream.javadsl.Source;
import akka.stream.testkit.javadsl.TestSink;
import org.junit.Test;
public class DataImporterUnitTest {
private final ActorSystem actorSystem = ActorSystem.create();
@Test
public void givenStreamOfIntegers_whenCalculateAverageOfPairs_thenShouldReturnProperResults() {
//given
Flow<String, Double, NotUsed> tested = new DataImporter(actorSystem).calculateAverage();
String input = "1;9;11;0";
//when
Source<Double, NotUsed> flow = Source.single(input).via(tested);
//then
flow
.runWith(TestSink.probe(actorSystem), ActorMaterializer.create(actorSystem))
.request(4)
.expectNextUnordered(5d, 5.5);
}
@Test
public void givenStreamOfIntegers_whenCalculateAverageAndSaveToSink_thenShouldFinishSuccessfully() {
//given
DataImporter dataImporter = new DataImporter(actorSystem);
String input = "10;90;110;10";
//when
dataImporter.calculateAverageForContent(input)
.thenAccept(d -> actorSystem.terminate());
}
}

34
akka-modules/pom.xml Normal file
View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>akka-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>akka-modules</name>
<packaging>pom</packaging>
<parent>
<artifactId>parent-modules</artifactId>
<groupId>com.baeldung</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modules>
<module>akka-http</module>
<module>akka-streams</module>
<module>spring-akka</module>
</modules>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

View File

@@ -0,0 +1,6 @@
## Spring Akka
This module contains articles about Spring with Akka
### Relevant Articles:
- [Introduction to Spring with Akka](https://www.baeldung.com/akka-with-spring)

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-akka</artifactId>
<version>0.1-SNAPSHOT</version>
<name>spring-akka</name>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>akka-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor_${scala.version}</artifactId>
<version>${akka.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>${spring.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<spring.version>4.3.4.RELEASE</spring.version>
<akka.version>2.4.14</akka.version>
<scala.version>2.11</scala.version>
</properties>
</project>

View File

@@ -0,0 +1,24 @@
package com.baeldung.akka;
import akka.actor.ActorSystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan
public class AppConfiguration {
@Autowired
private ApplicationContext applicationContext;
@Bean
public ActorSystem actorSystem() {
ActorSystem system = ActorSystem.create("akka-spring-demo");
SpringExtension.SPRING_EXTENSION_PROVIDER.get(system).initialize(applicationContext);
return system;
}
}

View File

@@ -0,0 +1,42 @@
package com.baeldung.akka;
import akka.actor.UntypedActor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class GreetingActor extends UntypedActor {
private GreetingService greetingService;
public GreetingActor(GreetingService greetingService) {
this.greetingService = greetingService;
}
@Override
public void onReceive(Object message) throws Throwable {
if (message instanceof Greet) {
String name = ((Greet) message).getName();
getSender().tell(greetingService.greet(name), getSelf());
} else {
unhandled(message);
}
}
public static class Greet {
private String name;
public Greet(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
}

View File

@@ -0,0 +1,12 @@
package com.baeldung.akka;
import org.springframework.stereotype.Component;
@Component
public class GreetingService {
public String greet(String name) {
return "Hello, " + name;
}
}

View File

@@ -0,0 +1,28 @@
package com.baeldung.akka;
import akka.actor.Actor;
import akka.actor.IndirectActorProducer;
import org.springframework.context.ApplicationContext;
public class SpringActorProducer implements IndirectActorProducer {
private ApplicationContext applicationContext;
private String beanActorName;
public SpringActorProducer(ApplicationContext applicationContext, String beanActorName) {
this.applicationContext = applicationContext;
this.beanActorName = beanActorName;
}
@Override
public Actor produce() {
return (Actor) applicationContext.getBean(beanActorName);
}
@Override
public Class<? extends Actor> actorClass() {
return (Class<? extends Actor>) applicationContext.getType(beanActorName);
}
}

View File

@@ -0,0 +1,32 @@
package com.baeldung.akka;
import akka.actor.AbstractExtensionId;
import akka.actor.ExtendedActorSystem;
import akka.actor.Extension;
import akka.actor.Props;
import org.springframework.context.ApplicationContext;
public class SpringExtension extends AbstractExtensionId<SpringExtension.SpringExt> {
public static final SpringExtension SPRING_EXTENSION_PROVIDER = new SpringExtension();
@Override
public SpringExt createExtension(ExtendedActorSystem system) {
return new SpringExt();
}
public static class SpringExt implements Extension {
private volatile ApplicationContext applicationContext;
public void initialize(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public Props props(String actorBeanName) {
return Props.create(SpringActorProducer.class, applicationContext, actorBeanName);
}
}
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@@ -0,0 +1,46 @@
package com.baeldung.akka;
import java.util.concurrent.TimeUnit;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.util.Timeout;
import com.baeldung.akka.GreetingActor.Greet;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import scala.concurrent.Await;
import scala.concurrent.Future;
import scala.concurrent.duration.FiniteDuration;
import static akka.pattern.Patterns.ask;
import static com.baeldung.akka.SpringExtension.SPRING_EXTENSION_PROVIDER;
@ContextConfiguration(classes = AppConfiguration.class)
public class SpringAkkaIntegrationTest extends AbstractJUnit4SpringContextTests {
@Autowired
private ActorSystem system;
@Test
public void whenCallingGreetingActor_thenActorGreetsTheCaller() throws Exception {
ActorRef greeter = system.actorOf(SPRING_EXTENSION_PROVIDER.get(system).props("greetingActor"), "greeter");
FiniteDuration duration = FiniteDuration.create(1, TimeUnit.SECONDS);
Timeout timeout = Timeout.durationToTimeout(duration);
Future<Object> result = ask(greeter, new Greet("John"), timeout);
Assert.assertEquals("Hello, John", Await.result(result, duration));
}
@After
public void tearDown() {
system.shutdown();
system.awaitTermination();
}
}