1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_framework.hxx"
26 
27 /*TODO
28     - change "singleton" behaviour by using new helper ::comhelper::SingletonRef
29     - rename method exist() to existHandlerForURL() or similar one
30     - may its a good idea to replace struct ProtocolHandler by css::beans::NamedValue type?!
31 */
32 
33 //_________________________________________________________________________________________________________________
34 //	my own includes
35 //_________________________________________________________________________________________________________________
36 
37 #include <classes/protocolhandlercache.hxx>
38 #include <classes/converter.hxx>
39 #include <threadhelp/readguard.hxx>
40 #include <threadhelp/writeguard.hxx>
41 #include <threadhelp/lockhelper.hxx>
42 
43 //_________________________________________________________________________________________________________________
44 //	interface includes
45 //_________________________________________________________________________________________________________________
46 
47 //_________________________________________________________________________________________________________________
48 //	other includes
49 //_________________________________________________________________________________________________________________
50 #include <tools/wldcrd.hxx>
51 #include <unotools/configpathes.hxx>
52 #include <rtl/ustrbuf.hxx>
53 
54 //_________________________________________________________________________________________________________________
55 //	namespace
56 //_________________________________________________________________________________________________________________
57 
58 namespace framework{
59 
60 //_________________________________________________________________________________________________________________
61 //  non exported const
62 //_________________________________________________________________________________________________________________
63 
64 //_________________________________________________________________________________________________________________
65 //  non exported definitions
66 //_________________________________________________________________________________________________________________
67 
68 /**
69     @short      overloaded index operator of hash map to support pattern key search
70     @descr      All keys inside this hash map are URL pattern which points to an uno
71                 implementation name of a protocol handler service which is registered
72                 for this pattern. This operator makes it easy to find such registered
73                 handler by using a full qualified URL and compare it with all pattern
74                 keys.
75 
76     @param      sURL
77                 the full qualified URL which should match to a registered pattern
78 
79     @return     An iterator which points to the found item inside the hash or PatternHash::end()
80                 if no pattern match this given <var>sURL</var>.
81 
82     @modified   30.04.2002 09:52, as96863
83  */
findPatternKey(const::rtl::OUString & sURL)84 PatternHash::iterator PatternHash::findPatternKey( const ::rtl::OUString& sURL )
85 {
86     PatternHash::iterator pItem = this->begin();
87     while( pItem!=this->end() )
88     {
89         WildCard aPattern(pItem->first);
90         if (aPattern.Matches(sURL))
91             break;
92         ++pItem;
93     }
94     return pItem;
95 }
96 
97 //_________________________________________________________________________________________________________________
98 
99 /**
100     @short      initialize static member of class HandlerCache
101     @descr      We use a singleton pattern to implement this handler cache.
102                 That means it use two static member list to hold all necessary informations
103                 and a ref count mechanism to create/destroy it on demand.
104 
105     @modified   30.04.2002 11:13, as96863
106  */
107 HandlerHash* HandlerCache::m_pHandler  = NULL;
108 PatternHash* HandlerCache::m_pPattern  = NULL;
109 sal_Int32    HandlerCache::m_nRefCount = 0   ;
110 HandlerCFGAccess* HandlerCache::m_pConfig = NULL;
111 
112 //_________________________________________________________________________________________________________________
113 
114 /**
115     @short      ctor of the cache of all registered protoco handler
116     @descr      It tries to open the right configuration package automatically
117                 and fill the internal structures. After that the cache can be
118                 used for read access on this data and perform some search
119                 operations on it.
120 
121     @modified   30.04.2002 10:02, as96863
122  */
HandlerCache()123 HandlerCache::HandlerCache()
124 {
125     /* SAFE */{
126         WriteGuard aGlobalLock( LockHelper::getGlobalLock() );
127 
128         if (m_nRefCount==0)
129         {
130             m_pHandler = new HandlerHash();
131             m_pPattern = new PatternHash();
132             m_pConfig  = new HandlerCFGAccess(PACKAGENAME_PROTOCOLHANDLER);
133             m_pConfig->read(&m_pHandler,&m_pPattern);
134             m_pConfig->setCache(this);
135         }
136 
137         ++m_nRefCount;
138     /* SAFE */}
139 }
140 
141 //_________________________________________________________________________________________________________________
142 
143 /**
144     @short      dtor of the cache
145     @descr      It frees all used memory. In further implementations (may if we support write access too)
146                 it's a good place to flush changes back to the configuration - but not needed yet.
147 
148     @modified   30.04.2002 09:54, as96863
149  */
~HandlerCache()150 HandlerCache::~HandlerCache()
151 {
152     /* SAFE */{
153         WriteGuard aGlobalLock( LockHelper::getGlobalLock() );
154 
155         if( m_nRefCount==1)
156         {
157             m_pConfig->setCache(NULL);
158             m_pHandler->free();
159             m_pPattern->free();
160 
161             delete m_pConfig;
162             delete m_pHandler;
163             delete m_pPattern;
164             m_pConfig = NULL;
165 			m_pHandler= NULL;
166 			m_pPattern= NULL;
167         }
168 
169         --m_nRefCount;
170     /* SAFE */}
171 }
172 
173 //_________________________________________________________________________________________________________________
174 
175 /**
176     @short      dtor of the cache
177     @descr      It frees all used memory. In further implementations (may if we support write access too)
178                 it's a good place to flush changes back to the configuration - but not needed yet.
179 
180     @modified   30.04.2002 09:54, as96863
181  */
search(const::rtl::OUString & sURL,ProtocolHandler * pReturn) const182 sal_Bool HandlerCache::search( const ::rtl::OUString& sURL, ProtocolHandler* pReturn ) const
183 {
184     sal_Bool bFound = sal_False;
185     /* SAFE */{
186         ReadGuard aReadLock( LockHelper::getGlobalLock() );
187         PatternHash::const_iterator pItem = m_pPattern->findPatternKey(sURL);
188         if (pItem!=m_pPattern->end())
189         {
190             *pReturn = (*m_pHandler)[pItem->second];
191             bFound = sal_True;
192         }
193     /* SAFE */}
194     return bFound;
195 }
196 
197 //_________________________________________________________________________________________________________________
198 
199 /**
200     @short      search for a registered handler by using an URL struct
201     @descr      We combine necessary parts of this struct to a valid URL string
202                 and call our other search method ...
203                 It's a helper for outside code.
204 
205     @modified   30.04.2002 09:54, as96863
206  */
search(const css::util::URL & aURL,ProtocolHandler * pReturn) const207 sal_Bool HandlerCache::search( const css::util::URL& aURL, ProtocolHandler* pReturn ) const
208 {
209     return search( aURL.Complete, pReturn );
210 }
211 
212 //_________________________________________________________________________________________________________________
213 
exists(const::rtl::OUString & sURL) const214 sal_Bool HandlerCache::exists( const ::rtl::OUString& sURL ) const
215 {
216     sal_Bool bFound = sal_False;
217     /* SAFE */{
218         ReadGuard aReadLock( LockHelper::getGlobalLock() );
219         PatternHash::const_iterator pItem = m_pPattern->findPatternKey(sURL);
220         bFound = pItem!=m_pPattern->end();
221     /* SAFE */}
222     return bFound;
223 }
224 
225 //_________________________________________________________________________________________________________________
takeOver(HandlerHash * pHandler,PatternHash * pPattern)226 void HandlerCache::takeOver(HandlerHash* pHandler, PatternHash* pPattern)
227 {
228     // SAFE ->
229     WriteGuard aWriteLock( LockHelper::getGlobalLock() );
230 
231     HandlerHash* pOldHandler = m_pHandler;
232     PatternHash* pOldPattern = m_pPattern;
233 
234     m_pHandler = pHandler;
235     m_pPattern = pPattern;
236 
237     pOldHandler->free();
238     pOldPattern->free();
239     delete pOldHandler;
240     delete pOldPattern;
241 
242     aWriteLock.unlock();
243     // <- SAFE
244 }
245 
246 //_________________________________________________________________________________________________________________
247 
248 /**
249     @short      dtor of the config access class
250     @descr      It opens the configuration package automatically by using base class mechanism.
251                 After that "read()" method of this class should be called to use it.
252 
253     @param      sPackage
254                 specifies the package name of the configuration data which should be used
255 
256     @modified   30.04.2002 10:06, as96863
257  */
HandlerCFGAccess(const::rtl::OUString & sPackage)258 HandlerCFGAccess::HandlerCFGAccess( const ::rtl::OUString& sPackage )
259     : ConfigItem( sPackage )
260 {
261     css::uno::Sequence< ::rtl::OUString > lListenPathes(1);
262     lListenPathes[0] = SETNAME_HANDLER;
263     EnableNotification(lListenPathes);
264 }
265 
266 //_________________________________________________________________________________________________________________
267 
268 /**
269     @short      use base class mechanism to fill given structures
270     @descr      User use us as a wrapper between configuration api and his internal structures.
271                 He give us some pointer to his member and we fill it.
272 
273     @param      pHandler
274                 pointer to a list of protocol handler infos
275 
276     @param      pPattern
277                 reverse map of handler pattern to her uno names
278 
279     @modified   30.04.2002 09:54, as96863
280  */
read(HandlerHash ** ppHandler,PatternHash ** ppPattern)281 void HandlerCFGAccess::read( HandlerHash** ppHandler ,
282                              PatternHash** ppPattern )
283 {
284     // list of all uno implementation names without encoding
285     css::uno::Sequence< ::rtl::OUString > lNames = GetNodeNames( SETNAME_HANDLER, ::utl::CONFIG_NAME_LOCAL_PATH );
286     sal_Int32 nSourceCount = lNames.getLength();
287     sal_Int32 nTargetCount = nSourceCount;
288     // list of all full qualified path names of configuration entries
289     css::uno::Sequence< ::rtl::OUString > lFullNames ( nTargetCount );
290 
291     // expand names to full path names
292     sal_Int32 nSource=0;
293     sal_Int32 nTarget=0;
294     for( nSource=0; nSource<nSourceCount; ++nSource )
295 	{
296         ::rtl::OUStringBuffer sPath( SETNAME_HANDLER );
297         sPath.append(CFG_PATH_SEPERATOR);
298         sPath.append(lNames[nSource]);
299         sPath.append(CFG_PATH_SEPERATOR);
300         sPath.append(PROPERTY_PROTOCOLS);
301 
302         lFullNames[nTarget]  = sPath.makeStringAndClear();
303         ++nTarget;
304     }
305 
306     // get values at all
307     css::uno::Sequence< css::uno::Any > lValues = GetProperties( lFullNames );
308     LOG_ASSERT2( lFullNames.getLength()!=lValues.getLength(), "HandlerCFGAccess::read()", "Miss some configuration values of handler set!" )
309 
310     // fill structures
311     nSource = 0;
312     for( nTarget=0; nTarget<nTargetCount; ++nTarget )
313 	{
314         // create it new for every loop to guarantee a real empty object!
315         ProtocolHandler aHandler;
316         aHandler.m_sUNOName = ::utl::extractFirstFromConfigurationPath(lNames[nSource]);
317 
318         // unpack all values of this handler
319         css::uno::Sequence< ::rtl::OUString > lTemp;
320         lValues[nTarget] >>= lTemp;
321         aHandler.m_lProtocols = Converter::convert_seqOUString2OUStringList(lTemp);
322 
323         // register his pattern into the performance search hash
324         for (OUStringList::iterator pItem =aHandler.m_lProtocols.begin();
325                                     pItem!=aHandler.m_lProtocols.end()  ;
326                                     ++pItem                             )
327         {
328             (**ppPattern)[*pItem] = lNames[nSource];
329         }
330 
331         // ï¿œnsert the handler info into the normal handler cache
332         (**ppHandler)[lNames[nSource]] = aHandler;
333         ++nSource;
334     }
335 }
336 
337 //_________________________________________________________________________________________________________________
Notify(const css::uno::Sequence<rtl::OUString> &)338 void HandlerCFGAccess::Notify(const css::uno::Sequence< rtl::OUString >& /*lPropertyNames*/)
339 {
340     HandlerHash* pHandler = new HandlerHash;
341     PatternHash* pPattern = new PatternHash;
342 
343     read(&pHandler, &pPattern);
344     if (m_pCache)
345         m_pCache->takeOver(pHandler, pPattern);
346     else
347     {
348         delete pHandler;
349         delete pPattern;
350     }
351 }
352 
Commit()353 void HandlerCFGAccess::Commit()
354 {
355 }
356 
357 } // namespace framework
358