Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/framework/source/fwi/classes/protocolhandlercache.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
/*TODO
21
    - change "singleton" behaviour by using new helper ::comhelper::SingletonRef
22
    - rename method exist() to existHandlerForURL() or similar one
23
    - may it's a good idea to replace struct ProtocolHandler by css::beans::NamedValue type?!
24
*/
25
26
#include <classes/protocolhandlercache.hxx>
27
#include <classes/converter.hxx>
28
29
#include <tools/wldcrd.hxx>
30
#include <unotools/configpaths.hxx>
31
#include <sal/log.hxx>
32
#include <vcl/svapp.hxx>
33
34
constexpr OUString SETNAME_HANDLER = u"HandlerSet"_ustr; // name of configuration set inside package
35
36
namespace framework{
37
38
/**
39
    @short      overloaded index operator of hash map to support pattern key search
40
    @descr      All keys inside this hash map are URL pattern which points to a uno
41
                implementation name of a protocol handler service which is registered
42
                for this pattern. This operator makes it easy to find such registered
43
                handler by using a full qualified URL and compare it with all pattern
44
                keys.
45
46
    @param      sURL
47
                the full qualified URL which should match to a registered pattern
48
49
    @return     An iterator which points to the found item inside the hash or PatternHash::end()
50
                if no pattern match this given <var>sURL</var>.
51
 */
52
namespace {
53
54
PatternHash::const_iterator findPatternKey(PatternHash const * hash, const OUString& sURL)
55
0
{
56
0
    return std::find_if(hash->begin(), hash->end(),
57
0
        [&sURL](const PatternHash::value_type& rEntry) {
58
0
            WildCard aPattern(rEntry.first);
59
0
            return aPattern.Matches(sURL);
60
0
        });
61
0
}
62
63
}
64
65
/**
66
    @short      initialize static member of class HandlerCache
67
    @descr      We use a singleton pattern to implement this handler cache.
68
                That means it use two static member list to hold all necessary information
69
                and a ref count mechanism to create/destroy it on demand.
70
 */
71
std::optional<HandlerHash> HandlerCache::s_pHandler;
72
std::optional<PatternHash> HandlerCache::s_pPattern;
73
sal_Int32    HandlerCache::m_nRefCount = 0;
74
HandlerCFGAccess* HandlerCache::s_pConfig = nullptr;
75
76
/**
77
    @short      ctor of the cache of all registered protocol handler
78
    @descr      It tries to open the right configuration package automatically
79
                and fill the internal structures. After that the cache can be
80
                used for read access on this data and perform some search
81
                operations on it.
82
 */
83
HandlerCache::HandlerCache()
84
8.34k
{
85
8.34k
    SolarMutexGuard aGuard;
86
87
8.34k
    if (m_nRefCount==0)
88
27
    {
89
27
        s_pHandler.emplace();
90
27
        s_pPattern.emplace();
91
27
        s_pConfig = new HandlerCFGAccess(PACKAGENAME_PROTOCOLHANDLER);
92
27
        s_pConfig->read(*s_pHandler, *s_pPattern);
93
27
        s_pConfig->setCache(this);
94
27
    }
95
96
8.34k
    ++m_nRefCount;
97
8.34k
}
98
99
/**
100
    @short      dtor of the cache
101
    @descr      It frees all used memory. In further implementations (may if we support write access too)
102
                it's a good place to flush changes back to the configuration - but not needed yet.
103
 */
104
HandlerCache::~HandlerCache()
105
4.57k
{
106
4.57k
    SolarMutexGuard aGuard;
107
108
4.57k
    if( m_nRefCount==1)
109
0
    {
110
0
        s_pConfig->setCache(nullptr);
111
112
0
        delete s_pConfig;
113
0
        s_pConfig = nullptr;
114
0
        s_pHandler.reset();
115
0
        s_pPattern.reset();
116
0
    }
117
118
4.57k
    --m_nRefCount;
119
4.57k
}
120
121
/**
122
    @short      dtor of the cache
123
    @descr      It frees all used memory. In further implementations (may if we support write access too)
124
                it's a good place to flush changes back to the configuration - but not needed yet.
125
 */
126
// static
127
bool HandlerCache::search( const OUString& sURL, ProtocolHandler* pReturn )
128
0
{
129
0
    bool bFound = false;
130
131
0
    SolarMutexGuard aGuard;
132
133
0
    PatternHash::const_iterator pItem = findPatternKey(s_pPattern ? &*s_pPattern : nullptr, sURL);
134
0
    if (pItem != s_pPattern->end())
135
0
    {
136
0
        *pReturn = (*s_pHandler)[pItem->second];
137
0
        bFound = true;
138
0
    }
139
140
0
    return bFound;
141
0
}
142
143
/**
144
    @short      search for a registered handler by using a URL struct
145
    @descr      We combine necessary parts of this struct to a valid URL string
146
                and call our other search method ...
147
                It's a helper for outside code.
148
 */
149
// static
150
bool HandlerCache::search( const css::util::URL& aURL, ProtocolHandler* pReturn )
151
0
{
152
0
    return search( aURL.Complete, pReturn );
153
0
}
154
155
// static
156
void HandlerCache::takeOver(HandlerHash aHandler, PatternHash aPattern)
157
0
{
158
0
    SolarMutexGuard aGuard;
159
160
0
    s_pHandler = std::move(aHandler);
161
0
    s_pPattern = std::move(aPattern);
162
0
}
163
164
/**
165
    @short      dtor of the config access class
166
    @descr      It opens the configuration package automatically by using base class mechanism.
167
                After that "read()" method of this class should be called to use it.
168
169
    @param      sPackage
170
                specifies the package name of the configuration data which should be used
171
 */
172
HandlerCFGAccess::HandlerCFGAccess( const OUString& sPackage )
173
27
    : ConfigItem(sPackage)
174
27
    , m_pCache(nullptr)
175
27
{
176
27
    css::uno::Sequence< OUString > lListenPaths { SETNAME_HANDLER };
177
27
    EnableNotification(lListenPaths);
178
27
}
179
180
/**
181
    @short      use base class mechanism to fill given structures
182
    @descr      User use us as a wrapper between configuration api and his internal structures.
183
                He give us some pointer to his member and we fill it.
184
185
    @param      rHandlerHash
186
                list of protocol handler infos
187
188
    @param      rPatternHash
189
                reverse map of handler pattern to her uno names
190
 */
191
void HandlerCFGAccess::read( HandlerHash& rHandlerHash, PatternHash& rPatternHash )
192
27
{
193
    // list of all uno implementation names without encoding
194
27
    css::uno::Sequence< OUString > lNames = GetNodeNames( SETNAME_HANDLER, ::utl::ConfigNameFormat::LocalPath );
195
27
    sal_Int32 nSourceCount = lNames.getLength();
196
27
    sal_Int32 nTargetCount = nSourceCount;
197
    // list of all full qualified path names of configuration entries
198
27
    css::uno::Sequence< OUString > lFullNames ( nTargetCount );
199
27
    auto lFullNamesRange = asNonConstRange(lFullNames);
200
    // expand names to full path names
201
27
    sal_Int32 nSource=0;
202
27
    sal_Int32 nTarget=0;
203
27
    for( nSource=0; nSource<nSourceCount; ++nSource )
204
0
    {
205
0
        lFullNamesRange[nTarget] =
206
0
            SETNAME_HANDLER +
207
0
            CFG_PATH_SEPARATOR +
208
0
            lNames[nSource] +
209
0
            CFG_PATH_SEPARATOR
210
0
            PROPERTY_PROTOCOLS;
211
212
0
        ++nTarget;
213
0
    }
214
215
    // get values at all
216
27
    css::uno::Sequence< css::uno::Any > lValues = GetProperties( lFullNames );
217
27
    SAL_WARN_IF( lFullNames.getLength()!=lValues.getLength(), "fwk", "HandlerCFGAccess::read(): Miss some configuration values of handler set!" );
218
219
    // fill structures
220
27
    nSource = 0;
221
27
    for( nTarget=0; nTarget<nTargetCount; ++nTarget )
222
0
    {
223
        // create it new for every loop to guarantee a real empty object!
224
0
        ProtocolHandler aHandler;
225
0
        aHandler.m_sUNOName = ::utl::extractFirstFromConfigurationPath(lNames[nSource]);
226
227
        // unpack all values of this handler
228
0
        css::uno::Sequence< OUString > lTemp;
229
0
        lValues[nTarget] >>= lTemp;
230
0
        aHandler.m_lProtocols = Converter::convert_seqOUString2OUStringList(lTemp);
231
232
        // register his pattern into the performance search hash
233
0
        for (auto const& item : aHandler.m_lProtocols)
234
0
        {
235
0
            rPatternHash[item] = lNames[nSource];
236
0
        }
237
238
        // insert the handler info into the normal handler cache
239
0
        rHandlerHash[lNames[nSource]] = std::move(aHandler);
240
0
        ++nSource;
241
0
    }
242
27
}
243
244
void HandlerCFGAccess::Notify(const css::uno::Sequence< OUString >& /*lPropertyNames*/)
245
0
{
246
0
    HandlerHash aHandler;
247
0
    PatternHash aPattern;
248
249
0
    read(aHandler, aPattern);
250
0
    if (m_pCache)
251
0
        framework::HandlerCache::takeOver(std::move(aHandler), std::move(aPattern));
252
0
}
253
254
void HandlerCFGAccess::ImplCommit()
255
0
{
256
0
}
257
258
} // namespace framework
259
260
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */