Browse Source

first commit

placidenduwayo 1 year ago
parent
commit
717ebcba83

+ 8
- 0
pom.xml View File

66
             <version>2.1.2</version>
66
             <version>2.1.2</version>
67
         </dependency>
67
         </dependency>
68
 
68
 
69
+        <!-- https://mvnrepository.com/artifact/io.spray/spray-json -->
70
+        <dependency>
71
+            <groupId>io.spray</groupId>
72
+            <artifactId>spray-json_2.12</artifactId>
73
+            <version>1.3.6</version>
74
+        </dependency>
75
+
76
+
69
     </dependencies>
77
     </dependencies>
70
 
78
 
71
     <build>
79
     <build>

+ 22
- 9
src/main/java/fr/natan/akkastreamfileprocessingapi/controller/MovieController.java View File

1
 package fr.natan.akkastreamfileprocessingapi.controller;
1
 package fr.natan.akkastreamfileprocessingapi.controller;
2
 
2
 
3
+import fr.natan.akkastreamfileprocessingapi.futurecompleteness.CompletableFutureResult;
3
 import fr.natan.akkastreamfileprocessingapi.models.Models;
4
 import fr.natan.akkastreamfileprocessingapi.models.Models;
4
 import fr.natan.akkastreamfileprocessingapi.service.AkkaStreamFileProcessing;
5
 import fr.natan.akkastreamfileprocessingapi.service.AkkaStreamFileProcessing;
5
 import org.springframework.http.HttpStatus;
6
 import org.springframework.http.HttpStatus;
6
 import org.springframework.http.ResponseEntity;
7
 import org.springframework.http.ResponseEntity;
8
+import org.springframework.scheduling.annotation.Async;
7
 import org.springframework.web.bind.annotation.PathVariable;
9
 import org.springframework.web.bind.annotation.PathVariable;
8
 import org.springframework.web.bind.annotation.RequestMapping;
10
 import org.springframework.web.bind.annotation.RequestMapping;
9
 import org.springframework.web.bind.annotation.RequestMethod;
11
 import org.springframework.web.bind.annotation.RequestMethod;
11
 import scala.collection.IndexedSeq;
13
 import scala.collection.IndexedSeq;
12
 import scala.concurrent.Future;
14
 import scala.concurrent.Future;
13
 
15
 
16
+import java.util.concurrent.CompletableFuture;
17
+import java.util.concurrent.ExecutionException;
18
+
19
+
14
 @SuppressWarnings("SpellCheckingInspection")
20
 @SuppressWarnings("SpellCheckingInspection")
15
 @RestController
21
 @RestController
16
 public class MovieController {
22
 public class MovieController {
22
     }
28
     }
23
 
29
 
24
     @RequestMapping(value = "/persons/id/{personID}", method = RequestMethod.GET)
30
     @RequestMapping(value = "/persons/id/{personID}", method = RequestMethod.GET)
25
-    private Future<Models.Person> getPersonByID(@PathVariable(name = "personID") String nconst){
26
-
27
-       return akkaStreamFilesProcessing.getPersonById(nconst);
31
+    private ResponseEntity<String> getPersonByID(@PathVariable(name = "personID") String personID) throws ExecutionException, InterruptedException {
32
+        Future<Models.Person> personFuture = akkaStreamFilesProcessing.getPersonById(personID);
33
+        CompletableFuture<Models.Person> completableFutureResult =
34
+                new CompletableFutureResult().buildcompletableFuture(personFuture);
28
 
35
 
36
+        return new ResponseEntity<>(completableFutureResult.get().toString(), HttpStatus.OK);
29
     }
37
     }
30
 
38
 
31
     @RequestMapping(value = "/persons/name/{primaryName}", method = RequestMethod.GET)
39
     @RequestMapping(value = "/persons/name/{primaryName}", method = RequestMethod.GET)
32
-    private Future<IndexedSeq<Models.Person>> getPersonByName(@PathVariable(name = "primaryName") String primaryName){
33
-        return akkaStreamFilesProcessing.getPersonByName(primaryName);
40
+    private ResponseEntity<IndexedSeq<String>> getPersonByName(@PathVariable(name = "primaryName") String primaryName) throws ExecutionException, InterruptedException {
41
+        Future<IndexedSeq<Models.Person>> personsFuture = akkaStreamFilesProcessing.getPersonByName(primaryName);
42
+        CompletableFuture completableFutureResult =new
43
+                CompletableFutureResult().buildCompletableFuture2(personsFuture);
44
+        IndexedSeq<String> list = (IndexedSeq<String>) completableFutureResult.get();
45
+        return new ResponseEntity<>(list, HttpStatus.OK);
34
     }
46
     }
35
 
47
 
36
     @RequestMapping(value = "/tvseries/{tvseriePrimaryTitle}", method = RequestMethod.GET)
48
     @RequestMapping(value = "/tvseries/{tvseriePrimaryTitle}", method = RequestMethod.GET)
37
-    private Future<IndexedSeq<Models.TvSeries>> getTvserieByPrimaryTitle(@PathVariable(name ="tvseriePrimaryTitle" ) String tvseriePrimaryTitle){
49
+    private Future<IndexedSeq<Models.TvSeries>> getTvserieByPrimaryTitle(@PathVariable(name = "tvseriePrimaryTitle") String tvseriePrimaryTitle) {
38
         return akkaStreamFilesProcessing.getTvSerieByPrimaryTitle(tvseriePrimaryTitle);
50
         return akkaStreamFilesProcessing.getTvSerieByPrimaryTitle(tvseriePrimaryTitle);
39
     }
51
     }
40
 
52
 
41
     @RequestMapping(value = "/tvseries/title/{tvSerieTitle}", method = RequestMethod.GET)
53
     @RequestMapping(value = "/tvseries/title/{tvSerieTitle}", method = RequestMethod.GET)
42
-    private Future<IndexedSeq<Models.Person>> getPersonsForTvSerie(@PathVariable(name = "tvSerieTitle") String tvSerieTitle){
43
-      return akkaStreamFilesProcessing.getTeamOfPersonsForTvSerie(tvSerieTitle);
54
+    @Async
55
+    private Future<IndexedSeq<Models.Person>> getPersonsForTvSerie(@PathVariable(name = "tvSerieTitle") String tvSerieTitle) {
56
+        return akkaStreamFilesProcessing.getTeamOfPersonsForTvSerie(tvSerieTitle);
44
     }
57
     }
45
 
58
 
46
     @RequestMapping(value = "/persons", method = RequestMethod.GET)
59
     @RequestMapping(value = "/persons", method = RequestMethod.GET)
47
-    private ResponseEntity<String> getAllPersons(){
60
+    private ResponseEntity<String> getAllPersons() {
48
         akkaStreamFilesProcessing.getAllPersons();
61
         akkaStreamFilesProcessing.getAllPersons();
49
         return new ResponseEntity<>("is running", HttpStatus.OK);
62
         return new ResponseEntity<>("is running", HttpStatus.OK);
50
     }
63
     }

src/main/java/fr/natan/akkastreamfileprocessingapi/controller/BusinessExceptionHandler.java → src/main/java/fr/natan/akkastreamfileprocessingapi/exceptionshandler/BusinessExceptionHandler.java View File

1
-package fr.natan.akkastreamfileprocessingapi.controller;
1
+package fr.natan.akkastreamfileprocessingapi.exceptionshandler;
2
 
2
 
3
 import fr.natan.akkastreamfileprocessingapi.businessexceptions.FileNotFoundException;
3
 import fr.natan.akkastreamfileprocessingapi.businessexceptions.FileNotFoundException;
4
 import fr.natan.akkastreamfileprocessingapi.businessexceptions.MovieNotFoundException;
4
 import fr.natan.akkastreamfileprocessingapi.businessexceptions.MovieNotFoundException;

+ 31
- 0
src/main/java/fr/natan/akkastreamfileprocessingapi/futurecompleteness/CompletableFutureResult.java View File

1
+package fr.natan.akkastreamfileprocessingapi.futurecompleteness;
2
+
3
+import scala.collection.IndexedSeq;
4
+import scala.concurrent.Future;
5
+
6
+import java.util.concurrent.CompletableFuture;
7
+import java.util.concurrent.Executors;
8
+
9
+
10
+public class CompletableFutureResult<T> {
11
+
12
+    public CompletableFuture<T> buildcompletableFuture(Future<T> future){
13
+        CompletableFuture<T> completableFuture = new CompletableFuture<>();
14
+        Executors.newCachedThreadPool().submit(()->{
15
+            Thread.sleep(500);
16
+            return completableFuture.complete(future.value().get().get());
17
+        });
18
+        return completableFuture;
19
+    }
20
+
21
+    public CompletableFuture<IndexedSeq<T>> buildCompletableFuture2(Future<IndexedSeq<T>> futures){
22
+        CompletableFuture<IndexedSeq<T>> completableFuture = new CompletableFuture<>();
23
+        Executors.newCachedThreadPool().submit(
24
+                ()->{
25
+                    Thread.sleep(500);
26
+                    return completableFuture.complete(futures.value().get().get().seq());
27
+                }
28
+        );
29
+        return completableFuture;
30
+    }
31
+}

+ 6
- 11
src/main/scala/fr/natan/akkastreamfileprocessingapi/models/Models.scala View File

2
 
2
 
3
 object Models {
3
 object Models {
4
 
4
 
5
-  final case class Person(
6
-                           nconst: String,
7
-                           primaryName: String,
8
-                           birthYear: String,
9
-                           deathYear: String,
10
-                           primaryProfession: List[String],
11
-                           knownForTitles: List[String]
12
-                         ) {
5
+  final case class Person(nconst: String, primaryName: String, birthYear: String, deathYear: String,
6
+                          primaryProfession: List[String], knownForTitles: List[String]) {
13
     override def toString: String = {
7
     override def toString: String = {
14
       "Person[person-ID:" + nconst +
8
       "Person[person-ID:" + nconst +
15
         ", primary-name:" + primaryName +
9
         ", primary-name:" + primaryName +
16
         ", birth-year:" + birthYear +
10
         ", birth-year:" + birthYear +
17
-        ", dearth year:" + deathYear +
18
-        ", primary profession:" + primaryProfession +
19
-      ", known-for-titles"+knownForTitles+
11
+        ", dearth-year:" + deathYear +
12
+        ", primary-profession:" + primaryProfession +
13
+        ", known-for-titles" + knownForTitles +
20
         "]"
14
         "]"
21
     }
15
     }
16
+
22
   }
17
   }
23
 
18
 
24
   final case class TvSeries(
19
   final case class TvSeries(

+ 1
- 1
src/main/scala/fr/natan/akkastreamfileprocessingapi/service/AkkaStreamFileProcessing.scala View File

6
 
6
 
7
 //noinspection SpellCheckingInspection,AccessorLikeMethodIsUnit
7
 //noinspection SpellCheckingInspection,AccessorLikeMethodIsUnit
8
 trait AkkaStreamFileProcessing {
8
 trait AkkaStreamFileProcessing {
9
-  def getPersonById(nconst: String): Future[Person]
9
+  def getPersonById(personID: String): Future[Person]
10
   def getPersonByName(primaryName: String): Future[IndexedSeq[Person]]
10
   def getPersonByName(primaryName: String): Future[IndexedSeq[Person]]
11
 
11
 
12
   def getTvSerieByPrimaryTitle(tvSerieTitle: String):Future[IndexedSeq[TvSeries]]
12
   def getTvSerieByPrimaryTitle(tvSerieTitle: String):Future[IndexedSeq[TvSeries]]

+ 45
- 45
src/main/scala/fr/natan/akkastreamfileprocessingapi/service/AkkaStreamFileProcessingImpl.scala View File

26
   implicit val actorSystem: ActorSystem = ActorSystem("AkkaStreamActor")
26
   implicit val actorSystem: ActorSystem = ActorSystem("AkkaStreamActor")
27
   implicit val logger: Logger = Logger(LoggerFactory.getLogger(this.getClass))
27
   implicit val logger: Logger = Logger(LoggerFactory.getLogger(this.getClass))
28
 
28
 
29
-  override def getPersonById(nconst: String): Future[Person] = {
29
+  override def getPersonById(personID: String): Future[Person] = {
30
     val source: Source[Map[String, String], _] = buildSource(inputFile = nameBasics)
30
     val source: Source[Map[String, String], _] = buildSource(inputFile = nameBasics)
31
-    val res = source
32
-      .via(flow = filterByPersonIdFlow(nconst = nconst))
31
+    val res: Future[Person] = source
32
+      .via(flow = filterByPersonIdFlow(nconst = personID))
33
       .runWith(Sink.head)
33
       .runWith(Sink.head)
34
 
34
 
35
     res.andThen {
35
     res.andThen {
90
     res
90
     res
91
   }
91
   }
92
 
92
 
93
-  private def getListOfPersonsIDByTvSerieID(tvSerieID: Future[Option[String]]): Future[IndexedSeq[Option[String]]] = {
93
+  private def getListOfPersonsIDByTvSerieID(tvSerieIdFuture: Future[Option[String]]): Future[IndexedSeq[Option[String]]] = {
94
     val source: Source[Map[String, String], _] = buildSource(inputFile = titlePrincipalsBasics)
94
     val source: Source[Map[String, String], _] = buildSource(inputFile = titlePrincipalsBasics)
95
     val res: Future[IndexedSeq[Option[String]]] = source
95
     val res: Future[IndexedSeq[Option[String]]] = source
96
       .filter((rowMaps: Map[String, String]) => {
96
       .filter((rowMaps: Map[String, String]) => {
97
-        rowMaps.getOrElse(key = "tconst", default = "") == tvSerieID.value.get.get.get
97
+        rowMaps.getOrElse(key = "tconst", default = "") == tvSerieIdFuture.value.get.get.get
98
       })
98
       })
99
       .map((rowMap: Map[String, String]) => {
99
       .map((rowMap: Map[String, String]) => {
100
         rowMap.get(key = "nconst")
100
         rowMap.get(key = "nconst")
104
     res
104
     res
105
   }
105
   }
106
 
106
 
107
-  private def getListOfPersonsForTvSerie(listPersonsIDs: Future[IndexedSeq[Option[String]]]): Future[IndexedSeq[Person]] = {
108
-    val source: Source[Map[String, String], _] = buildSource(inputFile = nameBasics)
107
+  private def getListOfPersonsForTvSerie(listPersonsIDsFuture: Future[IndexedSeq[Option[String]]]):
108
+  Future[IndexedSeq[Person]] = {
109
 
109
 
110
-    val res: Future[IndexedSeq[Person]] =
111
-      source
112
-        .filter((rowMaps: Map[String, String]) => {
113
-          listPersonsIDs.value.get.get.contains(rowMaps.get(key = "nconst"))
114
-        })
115
-        .map((rowMap: Map[String, String]) => {
116
-          buildPersonModel(rowMap)
117
-        })
118
-        .runWith(Sink.collection)
110
+    val source: Source[Map[String, String], _] = buildSource(inputFile = nameBasics)
111
+    val res: Future[IndexedSeq[Person]] = source
112
+      .filter((rowMaps: Map[String, String]) => {
113
+        listPersonsIDsFuture.value.get.get.contains(rowMaps.get(key = "nconst"))
114
+      })
115
+      .map((rowMap: Map[String, String]) => {
116
+        buildPersonModel(rowMap)
117
+      })
118
+      .runWith(Sink.collection)
119
 
119
 
120
     res
120
     res
121
   }
121
   }
126
     logger.info("STEP 1/3 START")
126
     logger.info("STEP 1/3 START")
127
     val tvSerieIDFuture: Future[Option[String]] = getTvSerieIdByPrimaryTitle(primaryTitle = tvSeriePrimaryTitle)
127
     val tvSerieIDFuture: Future[Option[String]] = getTvSerieIdByPrimaryTitle(primaryTitle = tvSeriePrimaryTitle)
128
 
128
 
129
-    val finalResult: Future[IndexedSeq[Person]] = tvSerieIDFuture.andThen({
130
-      case Failure(exception) => logger.error(s"$exception")
131
-      case Success(value: Option[String]) =>
132
-        logger.info(s"TvSerie ID: $value")
133
-        logger.info("STEP 1/3 END")
134
-    })
135
-      .flatMap({
136
-       _ =>
137
-         logger.info("STEP 2/3 START")
138
-         val listPersonIDsFuture: Future[IndexedSeq[Option[String]]] = getListOfPersonsIDByTvSerieID(tvSerieID = tvSerieIDFuture)
139
-          listPersonIDsFuture.andThen({
140
-            case Failure(exception) => logger.error(s"$exception")
141
-            case Success(value) =>
142
-              value.foreach((personID: Option[String]) => logger.info(s"Person ID:$personID"))
143
-              logger.info("STEP 2/3 END")
144
-          })
145
-            .flatMap({
146
-              future =>
147
-                logger.info("STEP 3/3 START")
148
-                val personsTeamFuture: Future[IndexedSeq[Person]] = getListOfPersonsForTvSerie(listPersonsIDs = listPersonIDsFuture)
149
-                personsTeamFuture.andThen({
150
-                  case Failure(exception) => logger.error(s"$exception")
151
-                  case Success(value: IndexedSeq[Person]) =>
152
-                    value.foreach((person: Person) => logger.info(s"${person.toString}"))
153
-                    logger.info("STEP 3/3 END")
154
-                })
155
-            })
129
+    val finalFuture: Future[IndexedSeq[Person]] =
130
+      tvSerieIDFuture.andThen({
131
+        case Failure(exception) => logger.error(s"$exception")
132
+        case Success(value: Option[String]) =>
133
+          logger.info(s"TvSerie ID: $value")
134
+          logger.info("STEP 1/3 END")
156
       })
135
       })
136
+        .flatMap({
137
+          _ =>
138
+            logger.info("STEP 2/3 START")
139
+            val listPersonIDsFuture: Future[IndexedSeq[Option[String]]] = getListOfPersonsIDByTvSerieID(tvSerieIdFuture = tvSerieIDFuture)
140
+            listPersonIDsFuture.andThen({
141
+              case Failure(exception) => logger.error(s"$exception")
142
+              case Success(value) =>
143
+                value.foreach((personID: Option[String]) => logger.info(s"Person ID:$personID"))
144
+                logger.info("STEP 2/3 END")
145
+            })
146
+              .flatMap({
147
+                future =>
148
+                  logger.info("STEP 3/3 START")
149
+                  val personsTeamFuture: Future[IndexedSeq[Person]] = getListOfPersonsForTvSerie(listPersonsIDsFuture = listPersonIDsFuture)
150
+                  personsTeamFuture.andThen({
151
+                    case Failure(exception) => logger.error(s"$exception")
152
+                    case Success(value: IndexedSeq[Person]) =>
153
+                      value.foreach((person: Person) => logger.info(s"${person.toString}"))
154
+                      logger.info("STEP 3/3 END")
155
+                  })
156
+              })
157
+        })
157
 
158
 
158
-    finalResult
159
+    finalFuture
159
   }
160
   }
160
 
161
 
161
-
162
   override def getAllPersons(): Unit = {
162
   override def getAllPersons(): Unit = {
163
     val personSource: Source[Map[String, String], _] = buildSource(inputFile = nameBasics)
163
     val personSource: Source[Map[String, String], _] = buildSource(inputFile = nameBasics)
164
     //graph
164
     //graph

Powered by TurnKey Linux.