framework: avoid re-creating protocol handler instances all the time

Once you install an extension that adds its own protocol handlers (e.g.
<https://github.com/niocs/ProtocolHandlerExtension>), DispatchProvider
re-creates this protocol handler every time the custom menu gets opened
or a command gets dispatched.

This allows the dispatch provider to avoid managing the lifecycle of
those protocol handler instances, but in case the constructor of those
handlers is expensive, this leads to performance problems.

Introduce a map of handler instances in DispatchProvider to avoid
unnecessary re-creation and re-initialization: these instances get the
same XFrame anyway (the DispatchProvider is owned by the frame), so this
is meant to be safe.

No testcase for this -- the problem is only visible if you have an UNO
service registered in the global UNO service registry, but by the time
our cppunit tests run, that is already a fixed list, so this would be
hard to test from code.

Change-Id: I6d69906a795a2d5a67706002d635b6cb3091b856
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133706
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
This commit is contained in:
Miklos Vajna
2022-05-02 21:59:28 +02:00
parent f8d35a20be
commit 3f768cddd2
2 changed files with 19 additions and 5 deletions
@@ -74,6 +74,8 @@ class DispatchProvider final : public ::cppu::WeakImplHelper< css::frame::XDispa
css::uno::WeakReference< css::frame::XFrame > m_xFrame;
/// cache of some other dispatch provider which are registered inside configuration to handle special URL protocols
HandlerCache m_aProtocolHandlerCache;
std::unordered_map<OUString, css::uno::Reference<css::frame::XDispatchProvider>>
m_aProtocolHandlers;
/* interface */
public:
+17 -5
View File
@@ -440,18 +440,30 @@ css::uno::Reference< css::frame::XDispatch > DispatchProvider::implts_searchProt
SolarMutexGuard g;
// create it
bool bInitialize = true;
try
{
xHandler.set(
css::uno::Reference<css::lang::XMultiServiceFactory>(m_xContext->getServiceManager(), css::uno::UNO_QUERY_THROW)
->createInstance(aHandler.m_sUNOName),
css::uno::UNO_QUERY);
// Only create the protocol handler instance once, the creation is expensive.
auto it = m_aProtocolHandlers.find(aHandler.m_sUNOName);
if (it == m_aProtocolHandlers.end())
{
xHandler.set(
css::uno::Reference<css::lang::XMultiServiceFactory>(m_xContext->getServiceManager(), css::uno::UNO_QUERY_THROW)
->createInstance(aHandler.m_sUNOName),
css::uno::UNO_QUERY);
m_aProtocolHandlers.emplace(aHandler.m_sUNOName, xHandler);
}
else
{
xHandler = it->second;
bInitialize = false;
}
}
catch(const css::uno::Exception&) {}
// look if initialization is necessary
css::uno::Reference< css::lang::XInitialization > xInit( xHandler, css::uno::UNO_QUERY );
if (xInit.is())
if (xInit.is() && bInitialize)
{
css::uno::Reference< css::frame::XFrame > xOwner( m_xFrame.get(), css::uno::UNO_QUERY );
SAL_WARN_IF(!xOwner.is(), "fwk", "DispatchProvider::implts_searchProtocolHandler(): Couldn't get reference to my owner frame. So I can't set may needed context information for this protocol handler.");