Remove ModeClassLoader

Instead of dynamically loading mode related classes, use Guice bindings
to select proper implementation based on configuration.

Change-Id: I47d21062a249d03118b1e0f8575b0cb0b047a3ae
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/PatchSetReviewer.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/PatchSetReviewer.java
index 187d7c2..719cb5e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/PatchSetReviewer.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/PatchSetReviewer.java
@@ -3,7 +3,6 @@
 import com.google.inject.Inject;
 import com.googlesource.gerrit.plugins.chatgpt.config.Configuration;
 import com.googlesource.gerrit.plugins.chatgpt.data.ChangeSetDataHandler;
-import com.googlesource.gerrit.plugins.chatgpt.mode.ModeClassLoader;
 import com.googlesource.gerrit.plugins.chatgpt.mode.common.client.api.gerrit.GerritChange;
 import com.googlesource.gerrit.plugins.chatgpt.mode.common.client.api.gerrit.GerritClient;
 import com.googlesource.gerrit.plugins.chatgpt.mode.common.client.api.gerrit.GerritClientReview;
@@ -33,19 +32,20 @@
     private final Configuration config;
     private final GerritClient gerritClient;
     private final ChangeSetData changeSetData;
-
     @Getter
-    private IChatGptClient chatGptClient;
+    private final IChatGptClient chatGptClient;
+
     private GerritCommentRange gerritCommentRange;
     private List<ReviewBatch> reviewBatches;
     private List<GerritComment> commentProperties;
     private List<Integer> reviewScores;
 
     @Inject
-    PatchSetReviewer(GerritClient gerritClient, Configuration config, ChangeSetData changeSetData) {
+    PatchSetReviewer(GerritClient gerritClient, Configuration config, ChangeSetData changeSetData, IChatGptClient chatGptClient) {
         this.config = config;
         this.gerritClient = gerritClient;
         this.changeSetData = changeSetData;
+        this.chatGptClient = chatGptClient;
     }
 
     public void review(GerritChange change) throws Exception {
@@ -131,8 +131,6 @@
             log.warn("Patch set too large. Skipping review. changeId: {}", change.getFullChangeId());
             return String.format(SPLIT_REVIEW_MSG, config.getMaxReviewLines());
         }
-        chatGptClient = (IChatGptClient) ModeClassLoader.getInstance(
-                "client.api.chatgpt.ChatGptClient", config);
         registerDynamicClasses(ChatGptClientStateless.class);
 
         return chatGptClient.ask(config, changeSetData, change, patchSet);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/listener/GerritEventContextModule.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/listener/GerritEventContextModule.java
index 9baa8ef..0d76a17 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/listener/GerritEventContextModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/listener/GerritEventContextModule.java
@@ -6,6 +6,12 @@
 import com.googlesource.gerrit.plugins.chatgpt.data.ChangeSetDataProvider;
 import com.googlesource.gerrit.plugins.chatgpt.mode.common.client.api.gerrit.GerritChange;
 import com.googlesource.gerrit.plugins.chatgpt.mode.common.model.data.ChangeSetData;
+import com.googlesource.gerrit.plugins.chatgpt.mode.interfaces.client.api.chatgpt.IChatGptClient;
+import com.googlesource.gerrit.plugins.chatgpt.mode.interfaces.client.api.gerrit.IGerritClientPatchSet;
+import com.googlesource.gerrit.plugins.chatgpt.mode.stateful.client.api.chatgpt.ChatGptClientStateful;
+import com.googlesource.gerrit.plugins.chatgpt.mode.stateful.client.api.gerrit.GerritClientPatchSetStateful;
+import com.googlesource.gerrit.plugins.chatgpt.mode.stateless.client.api.chatgpt.ChatGptClientStateless;
+import com.googlesource.gerrit.plugins.chatgpt.mode.stateless.client.api.gerrit.GerritClientPatchSetStateless;
 
 import static com.google.inject.Scopes.SINGLETON;
 
@@ -20,8 +26,25 @@
 
     @Override
     protected void configure() {
+        bind(IChatGptClient.class).to(getChatGptMode());
+        bind(IGerritClientPatchSet.class).to(getClientPatchSet());
+
         bind(Configuration.class).toInstance(config);
         bind(GerritChange.class).toInstance(new GerritChange(event));
         bind(ChangeSetData.class).toProvider(ChangeSetDataProvider.class).in(SINGLETON);
     }
+
+    private Class<? extends IChatGptClient> getChatGptMode() {
+        return switch (config.getGptMode()){
+            case stateful -> ChatGptClientStateful.class;
+            case stateless -> ChatGptClientStateless.class;
+        };
+    }
+
+    private Class<? extends IGerritClientPatchSet> getClientPatchSet() {
+        return switch (config.getGptMode()){
+            case stateful -> GerritClientPatchSetStateful.class;
+            case stateless -> GerritClientPatchSetStateless.class;
+        };
+    }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/ModeClassLoader.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/ModeClassLoader.java
deleted file mode 100644
index 4a67dfe..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/ModeClassLoader.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.googlesource.gerrit.plugins.chatgpt.mode;
-
-import com.googlesource.gerrit.plugins.chatgpt.config.Configuration;
-import com.googlesource.gerrit.plugins.chatgpt.utils.CustomClassLoader;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.ArrayList;
-
-import static com.googlesource.gerrit.plugins.chatgpt.utils.ClassUtils.createNewInstanceWithArgs;
-import static com.googlesource.gerrit.plugins.chatgpt.utils.ClassUtils.joinUsingDotNotation;
-import static com.googlesource.gerrit.plugins.chatgpt.utils.StringUtils.capitalizeFirstLetter;
-
-@Slf4j
-public class ModeClassLoader {
-    private static final String BASE_NAME = "com.googlesource.gerrit.plugins.chatgpt.mode";
-
-    public static Object getInstance(String className, Configuration config, Object... constructorArgs) {
-        CustomClassLoader customClassLoader = new CustomClassLoader();
-        String fullClassName = getFullClassName(className, config);
-        log.debug("Attempt to load Class '{}'", fullClassName);
-        try {
-            Class<?> DynamicallyLoadedClass = Class.forName(fullClassName, true, customClassLoader);
-            log.debug("Class '{}' loaded", fullClassName);
-            return createNewInstanceWithArgs(DynamicallyLoadedClass, constructorArgs);
-        } catch (ClassNotFoundException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    private static String getFullClassName(String className, Configuration config) {
-        String mode = config.getGptMode().name();
-        return joinUsingDotNotation(new ArrayList<>() {{
-            add(BASE_NAME);
-            add(mode);
-            add(className + capitalizeFirstLetter(mode));
-        }});
-    }
-
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/common/client/api/gerrit/GerritClientFacade.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/common/client/api/gerrit/GerritClientFacade.java
index 0da1a4e..ff744d1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/common/client/api/gerrit/GerritClientFacade.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/common/client/api/gerrit/GerritClientFacade.java
@@ -2,7 +2,6 @@
 
 import com.google.inject.Inject;
 import com.googlesource.gerrit.plugins.chatgpt.config.Configuration;
-import com.googlesource.gerrit.plugins.chatgpt.mode.ModeClassLoader;
 import com.googlesource.gerrit.plugins.chatgpt.mode.common.client.patch.diff.FileDiffProcessed;
 import com.googlesource.gerrit.plugins.chatgpt.mode.common.model.api.gerrit.GerritPermittedVotingRange;
 import com.googlesource.gerrit.plugins.chatgpt.mode.common.model.data.ChangeSetData;
@@ -24,10 +23,9 @@
     private final GerritClientComments gerritClientComments;
 
     @Inject
-    public GerritClientFacade(Configuration config, ChangeSetData changeSetData) {
+    public GerritClientFacade(Configuration config, ChangeSetData changeSetData, IGerritClientPatchSet gerritClientPatchSet) {
         gerritClientDetail = new GerritClientDetail(config, changeSetData);
-        gerritClientPatchSet = (IGerritClientPatchSet) ModeClassLoader.getInstance(
-                "client.api.gerrit.GerritClientPatchSet", config, config);
+        this.gerritClientPatchSet = gerritClientPatchSet;
         this.changeSetData = changeSetData;
         registerDynamicClasses(GerritClientPatchSetStateless.class, GerritClientPatchSetStateful.class);
         gerritClientComments = new GerritClientComments(config, changeSetData);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/api/gerrit/GerritClientPatchSetStateful.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/api/gerrit/GerritClientPatchSetStateful.java
index e563337..0b62eb0 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/api/gerrit/GerritClientPatchSetStateful.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/api/gerrit/GerritClientPatchSetStateful.java
@@ -1,5 +1,6 @@
 package com.googlesource.gerrit.plugins.chatgpt.mode.stateful.client.api.gerrit;
 
+import com.google.inject.Inject;
 import com.googlesource.gerrit.plugins.chatgpt.config.Configuration;
 import com.googlesource.gerrit.plugins.chatgpt.mode.common.model.data.ChangeSetData;
 import com.googlesource.gerrit.plugins.chatgpt.mode.stateful.client.api.chatgpt.ChatGptAssistant;
@@ -11,6 +12,7 @@
 @Slf4j
 public class GerritClientPatchSetStateful extends GerritClientPatchSet implements IGerritClientPatchSet {
 
+    @Inject
     public GerritClientPatchSetStateful(Configuration config) {
         super(config);
     }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateless/client/api/gerrit/GerritClientPatchSetStateless.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateless/client/api/gerrit/GerritClientPatchSetStateless.java
index a843172..531d872 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateless/client/api/gerrit/GerritClientPatchSetStateless.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateless/client/api/gerrit/GerritClientPatchSetStateless.java
@@ -2,6 +2,7 @@
 
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
+import com.google.inject.Inject;
 import com.googlesource.gerrit.plugins.chatgpt.config.Configuration;
 import com.googlesource.gerrit.plugins.chatgpt.mode.common.client.api.gerrit.GerritChange;
 import com.googlesource.gerrit.plugins.chatgpt.mode.common.client.api.gerrit.GerritClientPatchSet;
@@ -26,6 +27,7 @@
     private final List<String> diffs;
     private boolean isCommitMessage;
 
+    @Inject
     public GerritClientPatchSetStateless(Configuration config) {
         super(config);
         diffs = new ArrayList<>();
diff --git a/src/test/java/com/googlesource/gerrit/plugins/chatgpt/ChatGptReviewTestBase.java b/src/test/java/com/googlesource/gerrit/plugins/chatgpt/ChatGptReviewTestBase.java
index c63ec7e..4966a2a 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/chatgpt/ChatGptReviewTestBase.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/chatgpt/ChatGptReviewTestBase.java
@@ -33,7 +33,13 @@
 import com.googlesource.gerrit.plugins.chatgpt.mode.common.client.api.gerrit.GerritClient;
 import com.googlesource.gerrit.plugins.chatgpt.mode.common.client.api.gerrit.GerritClientFacade;
 import com.googlesource.gerrit.plugins.chatgpt.mode.common.model.data.ChangeSetData;
+import com.googlesource.gerrit.plugins.chatgpt.mode.interfaces.client.api.chatgpt.IChatGptClient;
+import com.googlesource.gerrit.plugins.chatgpt.mode.interfaces.client.api.gerrit.IGerritClientPatchSet;
+import com.googlesource.gerrit.plugins.chatgpt.mode.stateful.client.api.chatgpt.ChatGptClientStateful;
+import com.googlesource.gerrit.plugins.chatgpt.mode.stateful.client.api.gerrit.GerritClientPatchSetStateful;
 import com.googlesource.gerrit.plugins.chatgpt.mode.stateful.client.api.git.GitRepoFiles;
+import com.googlesource.gerrit.plugins.chatgpt.mode.stateless.client.api.chatgpt.ChatGptClientStateless;
+import com.googlesource.gerrit.plugins.chatgpt.mode.stateless.client.api.gerrit.GerritClientPatchSetStateless;
 import lombok.NonNull;
 import org.apache.http.entity.ContentType;
 import org.junit.Assert;
@@ -241,10 +247,10 @@
         prompts = gptRequestBody.get("messages").getAsJsonArray();
     }
 
-    private void initTest () throws NoSuchProjectException {
+    private void initTest() {
         ChangeSetData changeSetData = new ChangeSetData(GPT_USER_ACCOUNT_ID, config.getVotingMinScore(), config.getMaxReviewFileSize());
-        gerritClient = new GerritClient(new GerritClientFacade(config, changeSetData));
-        patchSetReviewer = new PatchSetReviewer(gerritClient, config, changeSetData);
+        gerritClient = new GerritClient(new GerritClientFacade(config, changeSetData, getGerritClientPatchSet()));
+        patchSetReviewer = new PatchSetReviewer(gerritClient, config, changeSetData, getChatGptClient());
         mockConfigCreator = mock(ConfigCreator.class);
     }
 
@@ -299,4 +305,18 @@
 
         return accountCache;
     }
+
+    private IChatGptClient getChatGptClient() {
+        return switch (config.getGptMode()) {
+            case stateful -> new ChatGptClientStateful();
+            case stateless -> new ChatGptClientStateless();
+        };
+    }
+
+    private IGerritClientPatchSet getGerritClientPatchSet() {
+        return switch (config.getGptMode()) {
+            case stateful -> new GerritClientPatchSetStateful(config);
+            case stateless -> new GerritClientPatchSetStateless(config);
+        };
+    }
 }