class LdapFilterPlugin extends AbstractLdapPlugin {

    private static final Logger LOGGER = Logger.getLogger(LdapFilterPlugin.class.getName());

    protected static final String FILTER_PARAM = "filter";
    protected static final String TRANSFORMS_PARAM = "transforms";
    private static final String SESSION_ALLOWED_PREFIX = "opengrok-filter-plugin-allowed";
    static final String INSTANCE = "instance";
    private String sessionAllowed = SESSION_ALLOWED_PREFIX;

    /**
     * List of configuration names.
     * <ul>
     * <li><code>filter</code> is LDAP filter used for searching (mandatory)</li>
     * <li><code>instance</code> is number of <code>LdapUserInstance</code> plugin to use (optional)</li>
     * <li><code>transforms</code> are comma separated string transforms, where each transform is name:value pair,
     * allowed values: <code>toLowerCase</code>, <code>toUpperCase</code></li>
     * </ul>
     */
    private String ldapFilter;
    private Integer ldapUserInstance;
    private Map<String, String> transforms;

    public LdapFilterPlugin() {
        sessionAllowed += "-" + nextId++;
    }

    @Override
    public void load(Map<String, Object> parameters) {<FILL_FUNCTION_BODY>}

    void loadTransforms(String transformsString) throws NullPointerException {
        transforms = new TreeMap<>();
        String[] transformsArray = transformsString.split(",");
        for (String elem: transformsArray) {
            String[] tran = elem.split(":");
            transforms.put(tran[0], tran[1]);
        }
        FilterUtil.checkTransforms(transforms);
    }

    @Override
    protected boolean sessionExists(HttpServletRequest req) {
        return super.sessionExists(req)
                && req.getSession().getAttribute(sessionAllowed) != null;
    }

    private String getSessionAttr() {
        return (LdapUserPlugin.SESSION_ATTR + (ldapUserInstance != null ? ldapUserInstance.toString() : ""));
    }

    @Override
    public void fillSession(HttpServletRequest req, User user) {
        LdapUser ldapUser;

        updateSession(req, false);

        if ((ldapUser = (LdapUser) req.getSession().getAttribute(getSessionAttr())) == null) {
            LOGGER.log(Level.WARNING, "failed to get LDAP attribute ''{0}'' from session for user {1}",
                    new Object[]{LdapUserPlugin.SESSION_ATTR, user});
            return;
        }

        String expandedFilter = expandFilter(ldapFilter, ldapUser, user);
        LOGGER.log(Level.FINEST, "expanded filter ''{0}'' for user {1} and LDAP user {2} into ''{3}''",
                new Object[]{ldapFilter, user, ldapUser, expandedFilter});
        AbstractLdapProvider ldapProvider = getLdapProvider();
        try {
            if ((ldapProvider.lookupLdapContent(null, expandedFilter)) == null) {
                LOGGER.log(Level.FINER,
                        "empty content for LDAP user {0} with filter ''{1}'' on {2}",
                        new Object[]{ldapUser, expandedFilter, ldapProvider});
                return;
            }
        } catch (LdapException ex) {
            throw new AuthorizationException(ex);
        }

        LOGGER.log(Level.FINER, "LDAP user {0} allowed on {1}",
                new Object[]{ldapUser, ldapProvider});
        updateSession(req, true);
    }

    /**
     * Expand {@code LdapUser} / {@code User} object attribute values into the filter.
     * Use \% for printing the '%' character.
     *
     * @param filter basic filter containing the special values
     * @param ldapUser user from LDAP
     * @param user user from the request
     * @return the filter with replacements
     * @see opengrok.auth.plugin.util.FilterUtil
     */
    String expandFilter(String filter, LdapUser ldapUser, User user) {

        filter = expandUserFilter(user, filter, transforms);

        for (Entry<String, Set<String>> entry : ldapUser.getAttributes().entrySet()) {
            if (entry.getValue().size() == 1) {
                String name = entry.getKey();
                String value = entry.getValue().iterator().next();
                try {
                    filter = replace(filter, name, value, transforms);
                } catch (PatternSyntaxException ex) {
                    LOGGER.log(Level.WARNING,
                            String.format("Failed to expand filter ''%s'' with name ''%s'' and value ''%s''",
                                    filter, name, value), ex);
                }
            }
        }

        filter = filter.replace("\\%", "%");

        return filter;
    }

    /**
     * Add a new allowed value into the session.
     *
     * @param req the request
     * @param allowed the new value
     */
    protected void updateSession(HttpServletRequest req, boolean allowed) {
        req.getSession().setAttribute(sessionAllowed, allowed);
    }

    @Override
    public boolean checkEntity(HttpServletRequest request, Project project) {
        return ((Boolean) Objects.requireNonNullElse(request.getSession().getAttribute(sessionAllowed), false));
    }

    @Override
    public boolean checkEntity(HttpServletRequest request, Group group) {
        return ((Boolean) Objects.requireNonNullElse(request.getSession().getAttribute(sessionAllowed), false));
    }
}

        super.load(parameters);

        if ((ldapFilter = (String) parameters.get(FILTER_PARAM)) == null) {
            throw new NullPointerException("Missing param [" + FILTER_PARAM + "] in the setup");
        }

        String instance = (String) parameters.get(INSTANCE);
        if (instance != null) {
            ldapUserInstance = Integer.parseInt(instance);
        }

        String transformsString = (String) parameters.get(TRANSFORMS_PARAM);
        if (transformsString != null) {
            loadTransforms(transformsString);
        }

        LOGGER.log(Level.FINE, "LdapFilter plugin loaded with filter={0}, instance={1}, transforms={2}",
                new Object[]{ldapFilter, ldapUserInstance, transforms});
    
<methods>public abstract boolean checkEntity(HttpServletRequest, org.opengrok.indexer.configuration.Project) ,public abstract boolean checkEntity(HttpServletRequest, org.opengrok.indexer.configuration.Group) ,public abstract void fillSession(HttpServletRequest, opengrok.auth.plugin.entity.User) ,public opengrok.auth.plugin.configuration.Configuration getConfiguration() ,public opengrok.auth.plugin.ldap.AbstractLdapProvider getLdapProvider() ,public boolean isAllowed(HttpServletRequest, org.opengrok.indexer.configuration.Project) ,public boolean isAllowed(HttpServletRequest, org.opengrok.indexer.configuration.Group) ,public void load(Map<java.lang.String,java.lang.Object>) ,public void unload() <variables>protected static final java.lang.String CONFIGURATION_PARAM,private static final Map<java.lang.String,opengrok.auth.plugin.configuration.Configuration> LOADED_CONFIGURATIONS,private static final java.lang.String SESSION_PREFIX,private opengrok.auth.plugin.configuration.Configuration cfg,private opengrok.auth.plugin.ldap.AbstractLdapProvider ldapProvider,protected static long nextId,protected java.lang.String sessionEstablished,protected java.lang.String sessionUsername