class SecurityServletFilter implements Filter {

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
            throws IOException, ServletException {

        // retrieve user header and make sure header is present and is not empty
        final String gpdbUser = getHeaderValue(request, USER_HEADER, true);
        final String transactionId = getHeaderValue(request, TRANSACTION_ID_HEADER, true);
        final Integer segmentId = getHeaderValueInt(request, SEGMENT_ID_HEADER, true);
        final boolean lastCallForSegment = getHeaderValueBoolean(request, LAST_FRAGMENT_HEADER, false);

        final String serverName = StringUtils.defaultIfBlank(getHeaderValue(request, SERVER_HEADER, false), "default");
        final String configDirectory = StringUtils.defaultIfBlank(getHeaderValue(request, CONFIG_HEADER, false), serverName);
        final Configuration configuration = configurationFactory.initConfiguration(configDirectory, serverName, gpdbUser, null);
        final boolean isUserImpersonation = secureLogin.isUserImpersonationEnabled(configuration);
        final boolean isSecurityEnabled = Utilities.isSecurityEnabled(configuration);

        // Establish the UGI for the login user or the Kerberos principal for the given server, if applicable
        UserGroupInformation loginUser = secureLogin.getLoginUser(serverName, configDirectory, configuration);

        String serviceUser = loginUser.getUserName();

        if (!isUserImpersonation && isSecurityEnabled) {
            // When impersonation is disabled and security is enabled
            // we check whether the pxf.service.user.name property was provided
            // and if provided we use the value as the remote user instead of
            // the principal defined in pxf.service.kerberos.principal. However,
            // the principal will need to have proxy privileges on hadoop.
            String pxfServiceUserName = configuration.get(SecureLogin.CONFIG_KEY_SERVICE_USER_NAME);
            if (StringUtils.isNotBlank(pxfServiceUserName)) {
                serviceUser = pxfServiceUserName;
            }
        }

        String remoteUser = (isUserImpersonation ? gpdbUser : serviceUser);

        SessionId session = new SessionId(
                segmentId,
                transactionId,
                remoteUser,
                serverName,
                isSecurityEnabled,
                loginUser);

        final String serviceUserName = serviceUser;

        // Prepare privileged action to run on behalf of proxy user
        PrivilegedExceptionAction<Boolean> action = () -> {
            LOG.debug("Performing request for gpdb_user = {} as [remote_user = {} service_user = {} login_user ={}] with{} impersonation",
                    gpdbUser, remoteUser, serviceUserName, loginUser.getUserName(), isUserImpersonation ? "" : "out");
            chain.doFilter(request, response);
            return true;
        };

        boolean exceptionDetected = false;
        try {
            // Retrieve proxy user UGI from the UGI of the logged in user
            UserGroupInformation userGroupInformation = ugiCache
                    .getUserGroupInformation(session, isUserImpersonation);

            LOG.debug("Retrieved proxy user {} for server {} and session {}", userGroupInformation, serverName, session);

            // Execute the servlet chain as that user
            userGroupInformation.doAs(action);
        } catch (UndeclaredThrowableException ute) {
            exceptionDetected = true;
            // unwrap the real exception thrown by the action
            throw new ServletException(ute.getCause());
        } catch (InterruptedException ie) {
            exceptionDetected = true;
            throw new ServletException(ie);
        } finally {
            // Optimization to cleanup the cache if it is the last fragment
            boolean releaseUgi = lastCallForSegment || exceptionDetected;
            LOG.debug("Releasing UGI from cache for session: {}. {}",
                    session, exceptionDetected
                            ? " Exception while processing"
                            : (lastCallForSegment ? " Processed last fragment for segment" : ""));
            try {
                ugiCache.release(session, releaseUgi);
            } catch (Throwable t) {
                LOG.error("Error releasing UGI from cache for session: {}", session, t);
            }
            if (releaseUgi) {
                LOG.info("Finished processing {}", session);
            }
        }
    }

    public  SecurityServletFilter();
      SecurityServletFilter(ConfigurationFactory configurationFactory, SecureLogin secureLogin, UGICache ugiCache);

}