Part 3.1: Implementing plugin functionality

This guide covers the basic steps in adding code to implement functionality for a plugin.

Prerequisites

Before using this guide ensure that you have created a new plugin using a Maven archetype and imported it into IntelliJ.

Write Java code to implement functionality

If you are familiar with writing Groovy code see: Groovy/Java equivalent code examples for a series of examples to help you get started when writing a plugin in Java.

The Maven archetype creates a blank plugin with the bare bones required to get started with writing a new plugin.

  1. Open the TitlePrefixPluginSearchLifeCyclePlugin file inside IntelliJ. Observe that the file is basically empty - the Maven archetype has added some basic methods that you need to implement but these are all empty.

  2. Hold Ctrl and click on SearchLifeCyclePlugin, it will open the underlying file with the documentation we added earlier.

    This lists a few options for us in how we can communicate with the Funnelback server.

    documented_search_life_cycle

    When developing other plugins, you could do this with any of the other interfaces you may need to use.

    In this tutorial, we will create a plugin which affects the titles of the search results. Looking at the methods above, postProcess is the logical place to implement the plugin functionality.

  3. Swap back to the TitlePrefixPluginSearchLifeCyclePlugin and add the following code:

    @Override
    public void postProcess(SearchLifeCycleContext searchLifeCycleContext, SearchTransaction transaction) {
      // This is where your code will go.
    }
    You might be able to press Ctrl+O at the same time to get a menu that generates this for you.

The code that implements the functionality of the plugin will be added to this method.

The code will implement the following:

  • Read a pattern that will be matched against each title from the results page configuration.

  • Examine each of the search results and replace the title if there is a match to the pattern.

Getting input from the data source or results pages configuration

This uses the getCurrentProfileConfig() method to read results page configuration.

Update the postProcess method:

package com.example.plugin.titleprefixplugin;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.funnelback.plugin.SearchLifeCyclePlugin;
import com.funnelback.publicui.search.model.transaction.SearchTransaction;

public class TitlePrefixPluginSearchLifeCyclePlugin implements SearchLifeCyclePlugin {

    private static final Logger log = LogManager.getLogger(TitlePrefixPluginSearchLifeCyclePlugin.class); (1)

    @Override public void postProcess(SearchTransaction transaction) {
        String prefixToMatch = transaction.getQuestion().getCurrentProfileConfig().get(PluginUtils.KEY_PREFIX + "pattern"); (2)
        String givenReplaceWith = transaction.getQuestion().getCurrentProfileConfig().get(PluginUtils.KEY_PREFIX + "replaceWith"); (3)

        if (prefixToMatch == null || prefixToMatch.isBlank()) {  (4)
            // There is no prefix configured, we can't do anything. Lets log a warning and abort.
            log.warn("Could not find a pattern specified at " + PluginUtils.KEY_PREFIX +  "pattern. The TitlePrefixPlugin will do nothing."); (5)
            return;
        }
        // We'll mark replaceWith as an optional key, if someone doesn't supply it, then we'll just remove the pattern configured.
        String replaceWithToUse = givenReplaceWith != null ? givenReplaceWith: ""; (6)
    }
}
1 A logging mechanism has already been set up for us. This will come in handy when we learn about debugging and logging later.
2 Read the pattern used for title comparisons from the results page configuration and assign it to prefixToMatch. The getCurrentProfileConfig helper method reads results page configuration. This call reads the value of the plugin.title-prefix-plugin.config.pattern key.
3 Read the replacement value from plugin.title-prefix-plugin.config.pattern in the results page configuration.
4 Check for the existence of the pattern configuration value because that is required for this plugin to run and it may have not been set in configuration. If the values are not set then the plugin can’t run so it should exit graciously.
5 Write a log message that indicates why this plugin is not running. This will help someone who has misconfigured the plugin to understand why it is not working.
6 Check that a replacement pattern (defined by the replaceWith option) is set. This option has been written to be optional - if it is not set in configuration then a default value is applied instead.

Change the titles which match the pattern

Update the postProcess method to modify the response that our search results have. Add the following lines to the end of the method:

transaction.getResponse().getResultPacket().getResults().stream().filter(result -> { (1)
    return result.getTitle().startsWith(prefixToMatch); (2)
}).forEach(matchingResult -> { (3)
    String modifiedTitle = matchingResult.getTitle().replace(prefixToMatch, replaceWithToUse); (4)
    matchingResult.setTitle(modifiedTitle); (5)
});
1 Iterate over each search result and apply a filter.
2 Filters the list by returning only the results whose titles start with the prefix that was set in configuration.
3 Go through the results which passed our filter.
4 Calculate the new title to use.
5 Modify the title to be the new title.

The functionality of the plugin has now been implemented in the source code.

Before we can build the plugin we need to create some documentation for the plugin.

Next steps

The next tutorial covers the creation of documentation for the plugin from a template.