class RequestBodyInterceptor implements RequestInterceptor {
    private static final Logger LOG = LoggerFactory.getLogger(RequestBodyInterceptor.class);

    public BodyConfig config;

    private volatile HttpHandler next;

    public RequestBodyInterceptor() {

        if (LOG.isInfoEnabled())
            LOG.info("RequestBodyInterceptor is loaded.");

        config = BodyConfig.load();
    }

    /**
     * Check the header starts with application/json and parse it into map or list
     * based on the first character "{" or "[".
     *
     * @param exchange HttpServerExchange
     * @throws Exception Exception
     */
    @Override
    public void handleRequest(final HttpServerExchange exchange) throws Exception {<FILL_FUNCTION_BODY>}

    private boolean handleBody(final HttpServerExchange ex, String body, String contentType) {

        if (this.isJsonData(contentType))
            return this.attachJsonBody(ex, body);

        else if (this.isXmlData(contentType))
            return this.attachXmlBody(ex, body);

        else if (this.isFormData(contentType))
            return this.attachFormDataBody(ex, body);

        else
            return false;
    }

    /**
     * Method used to parse the body into a Map or a List and attach it into exchange.
     *
     * @param ex - current exchange
     * @param str - byte buffer body as a string
     * @return - true if successful
     */
    public boolean attachJsonBody(final HttpServerExchange ex, String str) {
        str = str.trim();

        if (str.charAt(0) == JSON_MAP_OBJECT_STARTING_CHAR) {
            this.cacheRequestBody(ex, str);
            return this.parseJsonMapObject(ex, AttachmentConstants.REQUEST_BODY, str);

        } else if (str.charAt(0) == JSON_ARRAY_OBJECT_STARTING_CHAR) {
            this.cacheRequestBody(ex, str);
            return this.parseJsonArrayObject(ex, AttachmentConstants.REQUEST_BODY, str);
        }

        setExchangeStatus(ex, CONTENT_TYPE_MISMATCH, ContentType.APPLICATION_JSON.value());
        return false;
    }

    public boolean attachXmlBody(HttpServerExchange exchange, String s) {
        // TODO
        this.cacheRequestBody(exchange, s);
        return true;
    }

    /**
     * Method used to parse the body into FormData and attach it into exchange
     *
     * @param exchange exchange to be attached
     * @param s        the string of the  request body
     * @return boolean to indicate if attached.
     */
    public boolean attachFormDataBody(final HttpServerExchange exchange, String s) {
        // TODO
        this.cacheRequestBody(exchange, s);
        return true;
    }

    private void cacheRequestBody(HttpServerExchange exchange, String s) {
        if (this.config.isCacheRequestBody())
            exchange.putAttachment(AttachmentConstants.REQUEST_BODY_STRING, s);
    }

    @Override
    public HttpHandler getNext() {
        return next;
    }

    @Override
    public MiddlewareHandler setNext(final HttpHandler next) {
        Handlers.handlerNotNull(next);
        this.next = next;
        return this;
    }

    @Override
    public boolean isEnabled() {
        return config.isEnabled();
    }

    @Override
    public void register() {
        ModuleRegistry.registerModule(BodyConfig.CONFIG_NAME, RequestBodyInterceptor.class.getName(), Config.getNoneDecryptedInstance().getJsonMapConfigNoCache(BodyConfig.CONFIG_NAME), null);
    }

    @Override
    public void reload() {
        config.reload();
        ModuleRegistry.registerModule(BodyConfig.CONFIG_NAME, RequestBodyInterceptor.class.getName(), Config.getNoneDecryptedInstance().getJsonMapConfigNoCache(BodyConfig.CONFIG_NAME), null);
        if (LOG.isInfoEnabled())
            LOG.info("RequestBodyInterceptor is reloaded.");
    }

    @Override
    public boolean isRequiredContent() {
        return true;
    }
}

        if (LOG.isDebugEnabled())
            LOG.debug("RequestBodyInterceptor.handleRequest starts.");

        if (this.shouldAttachBody(exchange.getRequestHeaders())) {

            var existing = (PooledByteBuffer[]) exchange.getAttachment(AttachmentConstants.BUFFERED_REQUEST_DATA_KEY);

            if(LOG.isTraceEnabled())
                LOG.trace("request body exists in exchange attachment = {}", existing != null);

            if (existing != null) {

                if (LOG.isTraceEnabled())
                    LOG.trace("Attach request body requirement is met and the byte buffer pool exists.");

                var completeBody = BuffersUtils.toString(existing, StandardCharsets.UTF_8);
                var contentType = exchange.getRequestHeaders().getFirst(Headers.CONTENT_TYPE);

                if (LOG.isTraceEnabled()) {
                    // this config flag should only be enabled on non-production environment for troubleshooting purpose.
                    if(config.isLogFullRequestBody())
                        LOG.trace("contentType = " + contentType + " request body = " + completeBody);
                    else
                        LOG.trace("contentType = " + contentType + " request body = " + (completeBody.length() > 16384 ? completeBody.substring(0, 16384) : completeBody));
                }
                boolean attached = this.handleBody(exchange, completeBody, contentType);

                if (!attached && LOG.isErrorEnabled())
                    LOG.error("Failed to attach the request body to the exchange!");

                else if (LOG.isTraceEnabled())
                    LOG.trace("Request body was attached to exchange");

            } else if (LOG.isTraceEnabled())
                LOG.trace("Request body interceptor is skipped due to the request path is not in request-injection.appliedBodyInjectionPathPrefixes configuration");
        }

        if (LOG.isDebugEnabled())
            LOG.debug("RequestBodyInterceptor.handleRequest ends.");

    
<no_super_class>