tdf#153948: LanguageTool: cache the prepared request

So that when the same text is re-checked using different
settings (e.g., language), the cached result is not used.

Change-Id: Ic4ed63c6835f9d3935f1b9541c80822bb52313c2
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148200
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
diff --git a/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx b/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx
index fb82288..0856be3 100644
--- a/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx
+++ b/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx
@@ -224,17 +224,8 @@ ProofreadingResult SAL_CALL LanguageToolGrammarChecker::doProofreading(
    xRes.nBehindEndOfSentencePosition
        = std::min(xRes.nStartOfNextSentencePosition, aText.getLength());

    auto cachedResult = mCachedResults.find(aText);
    if (cachedResult != mCachedResults.end())
    {
        xRes.aErrors = cachedResult->second;
        return xRes;
    }

    tools::Long http_code = 0;
    std::string response_body;
    OUString langTag(aLocale.Language + "-" + aLocale.Country);

    OString postData;
    if (rLanguageOpts.getRestProtocol() == sDuden)
    {
        std::stringstream aStream;
@@ -245,16 +236,28 @@ ProofreadingResult SAL_CALL LanguageToolGrammarChecker::doProofreading(
        aTree.put("spellchecking-level", 3);
        aTree.put("correction-proposals", true);
        boost::property_tree::write_json(aStream, aTree);
        response_body = makeDudenHttpRequest(checkerURL, HTTP_METHOD::HTTP_POST,
                                             aStream.str().c_str(), http_code);
        postData = OString(aStream.str());
    }
    else
    {
        OString postData(OUStringToOString(Concat2View("text=" + aText + "&language=" + langTag),
                                           RTL_TEXTENCODING_UTF8));
        response_body = makeHttpRequest(checkerURL, HTTP_METHOD::HTTP_POST, postData, http_code);
        postData = OUStringToOString(Concat2View("text=" + aText + "&language=" + langTag),
                                     RTL_TEXTENCODING_UTF8);
    }

    if (auto cachedResult = mCachedResults.find(postData); cachedResult != mCachedResults.end())
    {
        xRes.aErrors = cachedResult->second;
        return xRes;
    }

    tools::Long http_code = 0;
    std::string response_body;
    if (rLanguageOpts.getRestProtocol() == sDuden)
        response_body
            = makeDudenHttpRequest(checkerURL, HTTP_METHOD::HTTP_POST, postData, http_code);
    else
        response_body = makeHttpRequest(checkerURL, HTTP_METHOD::HTTP_POST, postData, http_code);

    if (http_code != 200)
    {
        return xRes;
@@ -274,8 +277,7 @@ ProofreadingResult SAL_CALL LanguageToolGrammarChecker::doProofreading(
        parseProofreadingJSONResponse(xRes, response_body);
    }
    // cache the result
    mCachedResults.insert(
        std::pair<OUString, Sequence<SingleProofreadingError>>(aText, xRes.aErrors));
    mCachedResults.insert(std::make_pair(postData, xRes.aErrors));
    return xRes;
}

diff --git a/lingucomponent/source/spellcheck/languagetool/languagetoolimp.hxx b/lingucomponent/source/spellcheck/languagetool/languagetoolimp.hxx
index 0051385..0fc5edf 100644
--- a/lingucomponent/source/spellcheck/languagetool/languagetoolimp.hxx
+++ b/lingucomponent/source/spellcheck/languagetool/languagetoolimp.hxx
@@ -47,7 +47,7 @@ class LanguageToolGrammarChecker
                                  css::lang::XServiceInfo, css::lang::XServiceDisplayName>
{
    css::uno::Sequence<css::lang::Locale> m_aSuppLocales;
    o3tl::lru_map<OUString, css::uno::Sequence<css::linguistic2::SingleProofreadingError>>
    o3tl::lru_map<OString, css::uno::Sequence<css::linguistic2::SingleProofreadingError>>
        mCachedResults;
    LanguageToolGrammarChecker(const LanguageToolGrammarChecker&) = delete;
    LanguageToolGrammarChecker& operator=(const LanguageToolGrammarChecker&) = delete;