--- title: "Configure the Integration function" url: https://docs.catalyst.zoho.com/en/tutorials/githubbot/java/configure-integration-function/ description: "Build an extension on Zoho Cliq using Catalyst Integration Functions, that enables you to access and work with your GitHub repositories using a Cliq bot" last_updated: 2025-11-19T15:07:41Z service: All Services type: tutorial related_links: - name: "Integration Functions" url: /en/serverless/help/functions/integration-functions --- # Configure the Integration Function We will now configure the Integration function and add code to it. > **Note:** We will need to code and deploy the function to the Catalyst remote console before configuring the extension on Cliq, because we have to associate the extension with an existing function from the Catalyst console. The [Integration function's directory](https://docs.catalyst.zoho.com/en/serverless/help/functions/integration-functions)`functions/GithubExtension` contains: * The `MainClass.java` main function file * Handler files in the `com/handlers` folder * The `catalyst-config.json` configuration file * Java library files in the lib folder * `.classpath` and `.project` dependency files We will be coding `BotHandler.java`, `CommandHandler.java` and `FunctionHandler.java` in the `handlers` folder. We will also create a new class file `GithubConstants.java` in this directory and add code in it. > **Note:** Please go through the code in this section to make sure you fully understand it. We will discuss the code at the end of this section. Copy the code below and paste it into the respective files located in the `functions/GithubExtension/com/handlers` directory of your project using an IDE and save the files. **BotHandler.java** ```java package com.handlers; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Logger; import java.util.logging.Level; import org.json.JSONObject; import org.json.JSONArray; import org.json.JSONException; import com.fasterxml.jackson.databind.ObjectMapper; import com.zc.cliq.enums.ACTION_TYPE; import com.zc.cliq.enums.BANNER_STATUS; import com.zc.cliq.enums.BUTTON_TYPE; import com.zc.cliq.enums.CHANNEL_OPERATION; import com.zc.cliq.enums.SLIDE_TYPE; import com.zc.cliq.objects.Action; import com.zc.cliq.objects.ActionData; import com.zc.cliq.objects.BotDetails; import com.zc.cliq.objects.ButtonObject; import com.zc.cliq.objects.Confirm; import com.zc.cliq.objects.Message; import com.zc.cliq.objects.Slide; import com.zc.cliq.requests.BotCallHandlerRequest; import com.zc.cliq.requests.BotContextHandlerRequest; import com.zc.cliq.requests.BotMentionHandlerRequest; import com.zc.cliq.requests.BotMenuActionHandlerRequest; import com.zc.cliq.requests.BotMessageHandlerRequest; import com.zc.cliq.requests.BotParticipationHandlerRequest; import com.zc.cliq.requests.BotWebhookHandlerRequest; import com.zc.cliq.requests.BotWelcomeHandlerRequest; import com.zc.cliq.responses.BannerResponse; import com.zc.cliq.responses.CoreResponse; import com.zc.cliq.responses.WebhookHandlerResponse; // import com.zc.cliq.util.ZCCliqUtil; public class BotHandler implements com.zc.cliq.interfaces.BotHandler, CoreResponse { Logger LOGGER = Logger.getLogger(BotHandler.class.getName()); @Override public CoreResponse messageHandler(BotMessageHandlerRequest req) throws JSONException { LOGGER.log(Level.SEVERE, "class BotHandler method messageHandler"); String message = req.getMessage(); String text; if (message == null) { text = "Hello! How can I help you?"; } else if (message.equalsIgnoreCase("hello")) { text = "Hello! How can I help you?"; } else if (message.equalsIgnoreCase("webhooktoken")) { Message msg = Message.getInstance("Click on the token generation button below!"); ButtonObject btnObj = new ButtonObject(); btnObj.setType(BUTTON_TYPE.GREEN_OUTLINE); btnObj.setLabel("Create Webhook"); Action action = new Action(); action.setType(ACTION_TYPE.INVOKE_FUNCTION); ActionData actionData = new ActionData(); actionData.setName("authenticate"); // ** ENTER YOUR BUTTON FUNCTION NAME HERE ** action.setData(actionData); Confirm confirm = new Confirm(); confirm.setTitle("Generate Webhooks for a GitLab Project"); confirm.setDescription("Connect to GitLab Projects from within Cliq"); confirm.setInput("user_webhook_token"); action.setConfirm(confirm); btnObj.setAction(action); msg.addButton(btnObj); return (CoreResponse) msg; } else { text = "Sorry, I'm not programmed yet to do this :sad:"; } Message resp = Message.getInstance(text); return (CoreResponse) resp; } @Override public CoreResponse menuActionHandler(BotMenuActionHandlerRequest req) throws Exception { LOGGER.log(Level.SEVERE, "class BotHandler method menuActionHandler"); Message msg = Message.getInstance(); BotDetails bot = BotDetails.getInstance(GithubConstants.BOT_NAME); msg.setBot(bot); if (req.getActionName().equals("Repos")) { JSONArray reposArray = CommandHandler.getRepos(); if (reposArray.length() == 0) { msg.setText("There aren't are repos created yet."); } else { Slide slide = Slide.getInstance(); msg.setText("Here's a list of the *repositories*"); slide.setType(SLIDE_TYPE.TABLE); slide.setTitle("Repo details"); List headers = new ArrayList<>(); headers.add("Name"); headers.add("Private"); headers.add("Open Issues"); headers.add("Link"); // Use Map instead of JSONObject Map data = new HashMap<>(); data.put("headers", headers); // Use List instead of JSONArray List> rows = new ArrayList<>(); for (int i = 0; i < reposArray.length(); i++) { JSONObject repo = reposArray.optJSONObject(i); Map row = new HashMap<>(); row.put("Name", repo.optString("name")); row.put("Private", repo.optBoolean("private") ? "Yes" : "No"); row.put("Open Issues", repo.optString("open_issues_count")); row.put("Link", "[Click here](" + repo.optString("html_url") + ")"); rows.add(row); } data.put("rows", rows); slide.setData(data); msg.addSlide(slide); } } else { msg.setText("Menu action triggered :fist:"); } return (CoreResponse) msg; } @Override public WebhookHandlerResponse webhookHandler(BotWebhookHandlerRequest req) throws Exception { LOGGER.log(Level.SEVERE, "class BotHandler method webhookHandler"); JSONObject reqBody = req.getBody(); LOGGER.info(reqBody.toString()); JSONObject commitJson = reqBody.optJSONArray("commits").optJSONObject(0); /// message Message msg = Message.getInstance("A commit has been pushed !"); msg.setBot(BotDetails.getInstance(GithubConstants.BOT_NAME)); /// commit msg Slide commitMsg = Slide.getInstance(); commitMsg.setType(SLIDE_TYPE.TEXT); commitMsg.setTitle("Commit message"); commitMsg.setData(commitJson.optString("message")); msg.addSlide(commitMsg); // slide Slide details = Slide.getInstance(); details.setType(SLIDE_TYPE.LABEL); details.setTitle("Details"); JSONArray dataArray = new JSONArray(); JSONObject committer = new JSONObject(); committer.put("Committer", commitJson.optJSONObject("author").optString("username")); dataArray.put(committer); JSONObject repoName = new JSONObject(); repoName.put("Repo Name", reqBody.optJSONObject("repository").optString("name")); dataArray.put(repoName); JSONObject timestamp = new JSONObject(); timestamp.put("Timestamp", commitJson.optString("timestamp")); dataArray.put(timestamp); JSONObject compare = new JSONObject(); compare.put("Compare", "[Click here](" + reqBody.optString("compare") + ")"); dataArray.put(compare); details.setData(dataArray); LOGGER.log(Level.SEVERE, "printing array"); ObjectMapper mapper = new ObjectMapper(); LOGGER.log(Level.SEVERE, mapper.writeValueAsString(dataArray)); msg.addSlide(details); return (WebhookHandlerResponse) msg; } @Override public CoreResponse participationHandler(BotParticipationHandlerRequest req) throws Exception { LOGGER.log(Level.SEVERE, "class BotHandler method participationHandler"); String text; if (req.getOperation().equals(CHANNEL_OPERATION.ADDED)) { text = "Hi. Thanks for adding me to the channel :smile:"; } else if (req.getOperation().equals(CHANNEL_OPERATION.REMOVED)) { text = "Bye-Bye :bye-bye:"; } else { text = "I'm too a participant of this chat :wink:"; } Message msg = Message.getInstance(text); return (CoreResponse) msg; } @Override public Message welcomeHandler(BotWelcomeHandlerRequest req) { LOGGER.log(Level.SEVERE, "class BotHandler method welcomeHandler"); String uName = req.getUser() != null ? req.getUser().getFirstName() : "user"; String text = "Hello " + uName + ". Thank you for subscribing :smile:"; Message msg = Message.getInstance(text); return msg; } @Override public CoreResponse contextHandler(BotContextHandlerRequest req) { LOGGER.log(Level.SEVERE, "class BotHandler method contextHandler"); BannerResponse resp = new BannerResponse("", BANNER_STATUS.SUCCESS); if (req.getContextId().equals("personal_details")) { Map answers = req.getAnswers(); StringBuilder str = new StringBuilder(); str.append("Name: ").append(answers.get("name")).append("\n"); str.append("Department: ").append(answers.get("dept")).append("\n"); resp = new BannerResponse("Nice ! I have collected your info: \n" + str.toString(), BANNER_STATUS.SUCCESS); } return (CoreResponse) resp; } @Override public CoreResponse mentionHandler(BotMentionHandlerRequest req) { LOGGER.log(Level.SEVERE, "class BotHandler method mentionHandler"); String text = "Hey *" + req.getUser().getFirstName() + "*, thanks for mentioning me here. I'm from Catalyst city"; BannerResponse resp = new BannerResponse(text, BANNER_STATUS.SUCCESS); return (CoreResponse) resp; } @Override public void callHandler(BotCallHandlerRequest req) throws Exception { LOGGER.log(Level.SEVERE, "class BotHandler method callHandler"); return; } } ``` **CommandHandler.java** ```java package com.handlers; import java.util.logging.Logger; import java.util.logging.Level; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.json.JSONArray; import org.json.JSONObject; import com.zc.api.APIConstants.RequestMethod; import com.zc.api.APIRequest; import com.zc.cliq.enums.SLIDE_TYPE; import com.zc.cliq.objects.BotDetails; import com.zc.cliq.objects.CommandSuggestion; import com.zc.cliq.objects.Message; import com.zc.cliq.objects.Slide; import com.zc.cliq.requests.CommandHandlerRequest; import com.zc.cliq.responses.CoreResponse; import okhttp3.Response; public class CommandHandler implements com.zc.cliq.interfaces.CommandHandler { Logger LOGGER = Logger.getLogger(CommandHandler.class.getName()); @Override public CoreResponse executionHandler(CommandHandlerRequest req) throws Exception { LOGGER.log(Level.SEVERE, "class CommandHandler method executionHandler"); Message msg = Message.getInstance(); BotDetails bot = BotDetails.getInstance(GithubConstants.BOT_NAME); msg.setBot(bot); String commandName = req.getName(); if (commandName.equals("commits")) { List repoSuggestions = req.getSelections(); if (repoSuggestions == null || repoSuggestions.isEmpty()) { msg.setText("Please select a repo from the suggestions."); } else { String repoName = repoSuggestions.get(0).getTitle(); JSONArray commitsArray = getCommits(repoName); if (commitsArray.length() == 0) { msg.setText("There aren't are commits made yet."); } else { Slide slide = Slide.getInstance(); msg.setText("Here's a list of the latest " + GithubConstants.PER_PAGE + " commits made to the repository *" + repoName + "*."); slide.setType(SLIDE_TYPE.TABLE); slide.setTitle("Commit details"); List headers = new ArrayList<>(); headers.add("Date"); headers.add("Commit message"); headers.add("Committed by"); headers.add("Link"); // Use Map instead of JSONObject Map data = new HashMap<>(); data.put("headers", headers); // Use List instead of JSONArray List> rows = new ArrayList<>(); for (int i = 0; i < commitsArray.length(); i++) { JSONObject obj = commitsArray.optJSONObject(i); JSONObject commit = obj.optJSONObject("commit"); JSONObject author = commit.optJSONObject("author"); Map row = new HashMap<>(); row.put("Date", author.optString("date")); row.put("Commit message", commit.optString("message")); row.put("Committed by", author.optString("name")); row.put("Link", "[Click here](" + obj.optString("html_url") + ")"); rows.add(row); } data.put("rows", rows); slide.setData(data); msg.addSlide(slide); } } } else if (commandName.equals("issues")) { List repoSuggestions = req.getSelections(); if (repoSuggestions == null || repoSuggestions.isEmpty()) { msg.setText("Please select a repo from the suggestions."); } else { String repoName = repoSuggestions.get(0).getTitle(); JSONArray issuesArray = getIssues(repoName); if (issuesArray.length() == 0) { msg.setText("There aren't are issues raised yet."); } else { Slide slide = Slide.getInstance(); msg.setText("Here's a list of the latest " + GithubConstants.PER_PAGE + " issues raised to the repository *" + repoName + "*"); slide.setType(SLIDE_TYPE.TABLE); slide.setTitle("Issue details"); List headers = new ArrayList<>(); headers.add("Created At"); headers.add("Title"); headers.add("Created By"); headers.add("Link"); // Use Map instead of JSONObject Map data = new HashMap<>(); data.put("headers", headers); // Use List instead of JSONArray List> rows = new ArrayList<>(); for (int i = 0; i < issuesArray.length(); i++) { JSONObject issueObj = issuesArray.optJSONObject(i); Map row = new HashMap<>(); row.put("Created At", issueObj.optString("created_at")); row.put("Title", issueObj.optString("title")); row.put("Created By", issueObj.optJSONObject("user").optString("login")); row.put("Link", "[Click here](" + issueObj.optString("html_url") + ")"); rows.add(row); } data.put("rows", rows); slide.setData(data); msg.addSlide(slide); } } } else { msg.setText("Slash command executed"); } return (CoreResponse) msg; } @Override public List suggestionHandler(CommandHandlerRequest req) throws Exception { LOGGER.log(Level.SEVERE, "class CommandHandler method suggestionHandler"); List suggestionList = new ArrayList(); JSONArray reposArray = getRepos(); List repoNames = new ArrayList<>(); for (int i = 0; i < reposArray.length(); i++) { JSONObject repo = reposArray.optJSONObject(i); repoNames.add(repo.optString("name")); } if (req.getName().equals("commits") || req.getName().equals("issues")) { repoNames.forEach((name) -> { CommandSuggestion sugg = CommandSuggestion.getInstance(); sugg.setTitle(name); suggestionList.add(sugg); }); } return suggestionList; } public static JSONArray getRepos() throws Exception { APIRequest req = getRequestObj("https://api.github.com/user/repos"); req.executeRequest(); Response resp = req.getHttpResponse(); JSONArray reposArray = new JSONArray(resp.body().string()); return reposArray; } private String getUsername() throws Exception { LOGGER.log(Level.SEVERE, "class CommandHandler method getUsername"); APIRequest req = getRequestObj("https://api.github.com/user"); JSONObject respJson = new JSONObject(req.getResponse().getResponseJSON().get(0).toString()); return respJson.get("login").toString(); } private JSONArray getCommits(String repoName) throws Exception { LOGGER.log(Level.SEVERE, "class CommandHandler method getCommits"); APIRequest req = getRequestObj("https://api.github.com/repos/" + getUsername() + "/" + repoName + "/commits?per_page=" + GithubConstants.PER_PAGE); req.executeRequest(); Response resp = req.getHttpResponse(); JSONArray commitsArray = new JSONArray(resp.body().string()); return commitsArray; } private JSONArray getIssues(String repoName) throws Exception { LOGGER.log(Level.SEVERE, "class CommandHandler method getIssues"); APIRequest req = getRequestObj("https://api.github.com/repos/" + getUsername() + "/" + repoName + "/issues?per_page=" + GithubConstants.PER_PAGE); req.executeRequest(); Response resp = req.getHttpResponse(); JSONArray issuesArray = new JSONArray(resp.body().string()); return issuesArray; } private static APIRequest getRequestObj(String url) { APIRequest req = new APIRequest(); req.setUrl(url); req.setRequestMethod(RequestMethod.GET); req.setAuthNeeded(false); HashMap headers = new HashMap<>(); headers.put("Authorization", "Token " + GithubConstants.PERSONAL_ACCESS_TOKEN); req.setHeaders(headers); return req; } } ``` **FunctionHandler.java** ```java package com.handlers; import java.util.HashMap; import java.util.Map; import com.zc.cliq.objects.Form; import com.zc.cliq.objects.FormChangeResponse; import com.zc.cliq.objects.FormDynamicFieldResponse; import com.zc.cliq.objects.Message; import com.zc.cliq.objects.WidgetSection; import com.zc.cliq.requests.ButtonFunctionRequest; import com.zc.cliq.requests.FormFunctionRequest; import com.zc.cliq.requests.WidgetFunctionRequest; public class FunctionHandler implements com.zc.cliq.interfaces.FunctionHandler { @SuppressWarnings("unchecked") @Override public Message buttonFunctionHandler(ButtonFunctionRequest req) throws Exception { String text; if (req.getName().equals("authenticate")) { System.out.println("Arguments: " + req.getArguments()); text = req.getArguments().get("input").toString(); } else { text = "Button function executed"; } Message msg = Message.getInstance(text); return msg; } @Override public Message formSubmitHandler(FormFunctionRequest req) throws Exception { return Message.getInstance("Form submitted successfully"); } @Override public FormChangeResponse formChangeHandler(FormFunctionRequest req) throws Exception { FormChangeResponse resp = FormChangeResponse.getInstance(); return resp; } @Override public FormDynamicFieldResponse formDynamicFieldHandler(FormFunctionRequest req) throws Exception { FormDynamicFieldResponse resp = FormDynamicFieldResponse.getInstance(); return resp; } @Override public Form formViewHandler(FormFunctionRequest req) throws Exception { return Form.getInstance(); } @Override public WidgetSection widgetButtonHandler(WidgetFunctionRequest req) throws Exception { return getButtonsSection(); } private WidgetSection getButtonsSection() { WidgetSection buttonSection = WidgetSection.getInstance(); return buttonSection; } } ``` Next,create a new Java class file in the `handlers/directory` and name it ` GithubConstants.java`.Add the code given below to the file. **GithubConstants.java** ```java package com.handlers; public class GithubConstants { public static final String PERSONAL_ACCESS_TOKEN = "XXXXx"; public static final Integer PER_PAGE = 10; public static final String BOT_NAME = "github-bot"; } ``` > **Note:** After you copy and paste this code,**paste the personal access token that you obtained from GitHub** in Step 2 on line 6 in this code. The functions directory is now configured. Let's quickly go over the code of the handler classes.We will discuss the components specified here in detail while [configuring the extension](https://docs.catalyst.zoho.com/en/tutorials/githubbot/java/create-extension-on-cliq). * The `BotHandler.java` class contains the business logic of the GitHub bot component that we will configure in the Cliq extension. After you enable the chat bot, you can generate a webhook token to authenticate the connection to GitHub, list the details of your Git repositories, and obtain the details of the latest commits and issues in a repository. These actions are defined in this class. * The `CommandHandler.java` class handles the actions to be performed for the issues and commits commands. It also defines the suggestion handler that lists the repos of the Git account. The user must select a repo from the suggestion after entering the command, to execute the command for. `CommandHandler.java` also defines the APIs for fetching other information from the Git account. * The `FunctionHandler.java` class contains the business logic of the button function that authenticates the webhook token for GitHub. * The `GitHubConstants.java` class file stores the constant values of the function, such as the personal access token and the bot name.