diff --git a/.gitignore b/.gitignore index 71eee8c..4e7ea5b 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ target /RUNNING_PID /htmlReport *.iml +.DS_Store \ No newline at end of file diff --git a/app/actors/SourcesInfoActor.java b/app/actors/SourcesInfoActor.java index 501f3c5..7a707ee 100644 --- a/app/actors/SourcesInfoActor.java +++ b/app/actors/SourcesInfoActor.java @@ -21,8 +21,6 @@ public class SourcesInfoActor extends AbstractBehavior { /** HTTP client used to call external APIs (e.g., NewsAPI) and fetch JSON responses. */ private final WSClient wsClient; - /** API key read from configuration and attached to outbound API requests. */ - private final String apiKey; /** Cache to store list of sources information from the News Api */ private SourcesInfo cachedInfo = null; @@ -35,9 +33,11 @@ public interface Message {} */ public static class GetSourcesInfo implements Message { public final ActorRef replyTo; + public final String apiKey; - public GetSourcesInfo(ActorRef replyTo) { + public GetSourcesInfo(String apiKey, ActorRef replyTo) { this.replyTo = replyTo; + this.apiKey = apiKey; } } @@ -64,14 +64,13 @@ public SourcesInfoFailed(String error) { } } - public static Behavior create(WSClient wsClient, String apiKey) { - return Behaviors.setup(context -> new SourcesInfoActor(context, wsClient, apiKey)); + public static Behavior create(WSClient wsClient) { + return Behaviors.setup(context -> new SourcesInfoActor(context, wsClient)); } - private SourcesInfoActor(ActorContext context, WSClient wsClient, String apiKey) { + private SourcesInfoActor(ActorContext context, WSClient wsClient) { super(context); this.wsClient = wsClient; - this.apiKey = apiKey; } @Override @@ -91,7 +90,7 @@ private Behavior onGetSourcesInfo(GetSourcesInfo msg) { getContext().getLog().info("SourcesInfoActor processing request for all sources."); - SourcesInfo sourcesInfoModel = new SourcesInfo(this.apiKey); + SourcesInfo sourcesInfoModel = new SourcesInfo(msg.apiKey); CompletionStage future = sourcesInfoModel.fetchSourcesInfo(wsClient); future.whenComplete((ignored, error) -> { diff --git a/app/actors/SupervisorActor.java b/app/actors/SupervisorActor.java index bb12615..b41d91f 100644 --- a/app/actors/SupervisorActor.java +++ b/app/actors/SupervisorActor.java @@ -165,7 +165,7 @@ public static Behavior create(WSClient wsClient) { ); // create sourceInfo actor ActorRef sourcesInfoActor = context.spawn( - SourcesInfoActor.create(wsClient, apiKey), + SourcesInfoActor.create(wsClient), "sourcesInfoActor" ); context.getLog().info("sourceActor and sourcesInfoActor spawned and ready"); diff --git a/app/actors/UserActor.java b/app/actors/UserActor.java index 644f439..1e5a5ff 100644 --- a/app/actors/UserActor.java +++ b/app/actors/UserActor.java @@ -191,7 +191,6 @@ private static class SearchInstance { * @return behavior for handling user-specific messages * @author Nattamon Paiboon */ - // TODO rm cache public static Behavior create(String id, ActorRef newsActor, ActorRef rActor, ActorRef sentimentActor) { return Behaviors.setup(context -> new UserActor(id, context, newsActor, rActor, sentimentActor).behavior()); } @@ -207,7 +206,6 @@ public static Behavior create(String id, ActorRef ne * @param rActor reference to the ReadbailityActor for getting readability * @author Nattamon Paiboon */ - // TODO rm cache private UserActor(String id, ActorContext context, ActorRef newsActor, ActorRef rActor, ActorRef sentimentActor) { this.id = id; this.context = context; diff --git a/app/controllers/HomeController.java b/app/controllers/HomeController.java index 6623e6a..0964af3 100644 --- a/app/controllers/HomeController.java +++ b/app/controllers/HomeController.java @@ -41,9 +41,6 @@ public class HomeController extends Controller { /** API key read from configuration and attached to outbound API requests. */ private final String apiKey; - /** Asynchronous cache used to store session history and source data with a TTL. */ - private final AsyncCacheApi asyncCache; - private final ActorSystem actorSystem; private final ActorRef supervisorActor; @@ -57,17 +54,14 @@ public class HomeController extends Controller { * * @author Luan Tran, Nattamon Paiboon * @param ws the WSClient used to send HTTP requests to the News API - * @param asyncCache the cache used to store user search history and source information * @param config the application's configuration, which contains the API key */ @Inject - public HomeController(WSClient ws, AsyncCacheApi asyncCache, Config config, ActorSystem actorSystem) { + public HomeController(WSClient ws, Config config, ActorSystem actorSystem) { this.ws = ws; - this.asyncCache = asyncCache; this.apiKey = config.getString("api.key"); this.actorSystem = actorSystem; - // TODO rm cache this.supervisorActor = actorSystem.systemActorOf( SupervisorActor.create(ws), "SupervisorActor", Props.empty() ); @@ -145,7 +139,7 @@ public CompletionStage source(String identifier, String sourceName) { // Ask SourcesInfoActor for the list of all sources return AskPattern.ask( sourcesInfoActor, - (ActorRef replyTo) -> new SourcesInfoActor.GetSourcesInfo(replyTo), + (ActorRef replyTo) -> new SourcesInfoActor.GetSourcesInfo(this.apiKey, replyTo), Duration.ofSeconds(10), actorSystem.scheduler() ).thenCompose(infoResponse -> { diff --git a/conf/application.conf b/conf/application.conf index 6a91315..19f2aeb 100644 --- a/conf/application.conf +++ b/conf/application.conf @@ -13,5 +13,6 @@ api { # "test" "a482d6d109894277b9ec6a6d2f4e83e9", "1002d5e24b1a4a0b92719ed6281694a9", + "c3f75cdb287647839659a5d323e7d01a" ] } \ No newline at end of file diff --git a/test/actors/SourcesInfoActorTest.java b/test/actors/SourcesInfoActorTest.java index de1e6fd..a84d8b4 100644 --- a/test/actors/SourcesInfoActorTest.java +++ b/test/actors/SourcesInfoActorTest.java @@ -67,10 +67,10 @@ public void testGetSourcesInfo_Success() { when(mockResponse.getStatus()).thenReturn(200); when(mockResponse.asJson()).thenReturn(json); - ActorRef actor = testKit.spawn(SourcesInfoActor.create(mockWsClient, "key")); + ActorRef actor = testKit.spawn(SourcesInfoActor.create(mockWsClient)); TestProbe probe = testKit.createTestProbe(); - actor.tell(new SourcesInfoActor.GetSourcesInfo(probe.getRef())); + actor.tell(new SourcesInfoActor.GetSourcesInfo("key", probe.getRef())); SourcesInfoActor.SourcesInfoLoaded response = probe.expectMessageClass(SourcesInfoActor.SourcesInfoLoaded.class); assertNotNull(response.sourcesInfo); @@ -90,10 +90,10 @@ public void testGetSourcesInfo_Failure() { when(mockRequest.get()).thenReturn(CompletableFuture.completedFuture(mockResponse)); when(mockResponse.getStatus()).thenReturn(500); // Server error - ActorRef actor = testKit.spawn(SourcesInfoActor.create(mockWsClient, "key")); + ActorRef actor = testKit.spawn(SourcesInfoActor.create(mockWsClient)); TestProbe probe = testKit.createTestProbe(); - actor.tell(new SourcesInfoActor.GetSourcesInfo(probe.getRef())); + actor.tell(new SourcesInfoActor.GetSourcesInfo("key", probe.getRef())); SourcesInfoActor.SourcesInfoFailed response = probe.expectMessageClass(SourcesInfoActor.SourcesInfoFailed.class); assertNotNull(response.error); @@ -115,15 +115,15 @@ public void testGetSourcesInfo_Caching() { when(mockResponse.getStatus()).thenReturn(200); when(mockResponse.asJson()).thenReturn(json); - ActorRef actor = testKit.spawn(SourcesInfoActor.create(mockWsClient, "key")); + ActorRef actor = testKit.spawn(SourcesInfoActor.create(mockWsClient)); TestProbe probe = testKit.createTestProbe(); // 1st Call - actor.tell(new SourcesInfoActor.GetSourcesInfo(probe.getRef())); + actor.tell(new SourcesInfoActor.GetSourcesInfo("key", probe.getRef())); probe.expectMessageClass(SourcesInfoActor.SourcesInfoLoaded.class); // 2nd Call: Hits Cache - actor.tell(new SourcesInfoActor.GetSourcesInfo(probe.getRef())); + actor.tell(new SourcesInfoActor.GetSourcesInfo("key", probe.getRef())); probe.expectMessageClass(SourcesInfoActor.SourcesInfoLoaded.class); // Verify API called ONCE