bump product version to 4.1.6.2
[LibreOffice.git] / framework / source / accelerators / storageholder.cxx
blob395c9943b7a3f834776a8f38d7f3f77efd6ae164
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <accelerators/storageholder.hxx>
22 #include <threadhelp/readguard.hxx>
23 #include <threadhelp/writeguard.hxx>
24 #include <services.h>
26 #include <com/sun/star/container/NoSuchElementException.hpp>
28 #include <com/sun/star/container/XNameAccess.hpp>
30 #include <com/sun/star/beans/XPropertySet.hpp>
32 #include <com/sun/star/embed/ElementModes.hpp>
34 #include <com/sun/star/embed/XTransactedObject.hpp>
36 #include <com/sun/star/embed/XPackageStructureCreator.hpp>
38 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
40 #include <com/sun/star/io/XSeekable.hpp>
43 #define PATH_SEPARATOR_ASCII "/"
44 #define PATH_SEPARATOR_UNICODE ((sal_Unicode)'/')
45 #define PATH_SEPARATOR OUString(PATH_SEPARATOR_ASCII)
48 namespace framework
51 //-----------------------------------------------
52 StorageHolder::StorageHolder()
53 : ThreadHelpBase( )
57 //-----------------------------------------------
58 StorageHolder::~StorageHolder()
60 // TODO implement me
61 // dispose/clear etcpp.
64 //-----------------------------------------------
65 void StorageHolder::forgetCachedStorages()
67 // SAFE -> ----------------------------------
68 WriteGuard aWriteLock(m_aLock);
70 TPath2StorageInfo::iterator pIt;
71 for ( pIt = m_lStorages.begin();
72 pIt != m_lStorages.end() ;
73 ++pIt )
75 TStorageInfo& rInfo = pIt->second;
76 // TODO think about listener !
77 rInfo.Storage.clear();
79 m_lStorages.clear();
81 aWriteLock.unlock();
82 // <- SAFE ----------------------------------
85 //-----------------------------------------------
86 void StorageHolder::setRootStorage(const css::uno::Reference< css::embed::XStorage >& xRoot)
88 // SAFE -> ----------------------------------
89 WriteGuard aWriteLock(m_aLock);
90 m_xRoot = xRoot;
91 aWriteLock.unlock();
92 // <- SAFE ----------------------------------
95 //-----------------------------------------------
96 css::uno::Reference< css::embed::XStorage > StorageHolder::getRootStorage() const
98 // SAFE -> ----------------------------------
99 ReadGuard aReadLock(m_aLock);
100 return m_xRoot;
101 // <- SAFE ----------------------------------
104 //-----------------------------------------------
105 css::uno::Reference< css::embed::XStorage > StorageHolder::openPath(const OUString& sPath ,
106 sal_Int32 nOpenMode)
108 OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
109 OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath);
111 // SAFE -> ----------------------------------
112 ReadGuard aReadLock(m_aLock);
113 css::uno::Reference< css::embed::XStorage > xParent = m_xRoot;
114 aReadLock.unlock();
115 // <- SAFE ----------------------------------
117 css::uno::Reference< css::embed::XStorage > xChild ;
118 OUString sRelPath;
119 OUStringList::const_iterator pIt ;
121 for ( pIt = lFolders.begin();
122 pIt != lFolders.end() ;
123 ++pIt )
125 const OUString& sChild = *pIt;
126 OUString sCheckPath (sRelPath);
127 sCheckPath += sChild;
128 sCheckPath += PATH_SEPARATOR;
130 // SAFE -> ------------------------------
131 aReadLock.lock();
133 // If we found an already open storage ... we must increase
134 // its use count. Otherwhise it will may be closed to early :-)
135 TPath2StorageInfo::iterator pCheck = m_lStorages.find(sCheckPath);
136 TStorageInfo* pInfo = 0;
137 if (pCheck != m_lStorages.end())
139 pInfo = &(pCheck->second);
140 ++(pInfo->UseCount);
141 xChild = pInfo->Storage;
143 else
145 aReadLock.unlock();
146 // <- SAFE ------------------------------
150 xChild = StorageHolder::openSubStorageWithFallback(xParent, sChild, nOpenMode, sal_True); // TODO think about delegating fallback decision to our own calli!
152 catch(const css::uno::RuntimeException&)
153 { throw; }
154 catch(const css::uno::Exception&)
156 /* TODO URGENT!
157 in case we found some "already existing storages" on the path before and increased its UseCount ...
158 and now we will get an exception on creating a new sub storage ...
159 we must decrease all UseCounts, which was touched before. Otherwise these storages cant be closed!
161 Idea: Using of another structure member "PossibleUseCount" as vector of unique numbers.
162 Every thread use another unique number to identify all "owned candidates".
163 A flush method with the same unique number force increasing of the "UseCount" variable then
164 inside a synchronized block ...
166 throw;
169 // SAFE -> ------------------------------
170 WriteGuard aWriteLock(m_aLock);
171 pInfo = &(m_lStorages[sCheckPath]);
172 pInfo->Storage = xChild;
173 pInfo->UseCount = 1;
174 aWriteLock.unlock();
175 // <- SAFE ------------------------------
178 xParent = xChild;
179 sRelPath += sChild;
180 sRelPath += PATH_SEPARATOR;
183 // TODO think about return last storage as working storage ... but dont caching it inside this holder!
184 // => otherwise the same storage is may be commit more then once.
186 return xChild;
189 //-----------------------------------------------
190 StorageHolder::TStorageList StorageHolder::getAllPathStorages(const OUString& sPath)
192 OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
193 OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath);
195 StorageHolder::TStorageList lStoragesOfPath;
196 OUString sRelPath ;
197 OUStringList::const_iterator pIt ;
199 // SAFE -> ----------------------------------
200 ReadGuard aReadLock(m_aLock);
202 for ( pIt = lFolders.begin();
203 pIt != lFolders.end() ;
204 ++pIt )
206 const OUString& sChild = *pIt;
207 OUString sCheckPath (sRelPath);
208 sCheckPath += sChild;
209 sCheckPath += PATH_SEPARATOR;
211 TPath2StorageInfo::iterator pCheck = m_lStorages.find(sCheckPath);
212 if (pCheck == m_lStorages.end())
214 // at least one path element was not found
215 // Seems that this path isnt open ...
216 lStoragesOfPath.clear();
217 return lStoragesOfPath;
220 TStorageInfo& rInfo = pCheck->second;
221 lStoragesOfPath.push_back(rInfo.Storage);
223 sRelPath += sChild;
224 sRelPath += PATH_SEPARATOR;
227 aReadLock.unlock();
228 // <- SAFE ----------------------------------
230 return lStoragesOfPath;
233 //-----------------------------------------------
234 void StorageHolder::commitPath(const OUString& sPath)
236 StorageHolder::TStorageList lStorages = getAllPathStorages(sPath);
238 css::uno::Reference< css::embed::XTransactedObject > xCommit;
239 StorageHolder::TStorageList::reverse_iterator pIt;
240 for ( pIt = lStorages.rbegin(); // order of commit is important ... otherwise changes are not recognized!
241 pIt != lStorages.rend() ;
242 ++pIt )
244 xCommit = css::uno::Reference< css::embed::XTransactedObject >(*pIt, css::uno::UNO_QUERY);
245 if (!xCommit.is())
246 continue;
247 xCommit->commit();
250 // SAFE -> ------------------------------
251 ReadGuard aReadLock(m_aLock);
252 xCommit = css::uno::Reference< css::embed::XTransactedObject >(m_xRoot, css::uno::UNO_QUERY);
253 aReadLock.unlock();
254 // <- SAFE ------------------------------
256 if (xCommit.is())
257 xCommit->commit();
260 //-----------------------------------------------
261 void StorageHolder::closePath(const OUString& rPath)
263 OUString sNormedPath = StorageHolder::impl_st_normPath(rPath);
264 OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath);
266 /* convert list of paths in the following way:
267 [0] = "path_1" => "path_1
268 [1] = "path_2" => "path_1/path_2"
269 [2] = "path_3" => "path_1/path_2/path_3"
271 OUStringList::iterator pIt1 ;
272 OUString sParentPath;
273 for ( pIt1 = lFolders.begin();
274 pIt1 != lFolders.end() ;
275 ++pIt1 )
277 OUString sCurrentRelPath = sParentPath;
278 sCurrentRelPath += *pIt1;
279 sCurrentRelPath += PATH_SEPARATOR;
280 *pIt1 = sCurrentRelPath;
281 sParentPath = sCurrentRelPath;
284 // SAFE -> ------------------------------
285 ReadGuard aReadLock(m_aLock);
287 OUStringList::reverse_iterator pIt2;
288 for ( pIt2 = lFolders.rbegin();
289 pIt2 != lFolders.rend() ;
290 ++pIt2 )
292 OUString sPath = *pIt2;
293 TPath2StorageInfo::iterator pPath = m_lStorages.find(sPath);
294 if (pPath == m_lStorages.end())
295 continue; // ???
297 TStorageInfo& rInfo = pPath->second;
298 --rInfo.UseCount;
299 if (rInfo.UseCount < 1)
301 rInfo.Storage.clear();
302 m_lStorages.erase(pPath);
306 aReadLock.unlock();
307 // <- SAFE ------------------------------
310 //-----------------------------------------------
311 void StorageHolder::notifyPath(const OUString& sPath)
313 OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
315 // SAFE -> ------------------------------
316 ReadGuard aReadLock(m_aLock);
318 TPath2StorageInfo::iterator pIt1 = m_lStorages.find(sNormedPath);
319 if (pIt1 == m_lStorages.end())
320 return;
322 TStorageInfo& rInfo = pIt1->second;
323 TStorageListenerList::iterator pIt2;
324 for ( pIt2 = rInfo.Listener.begin();
325 pIt2 != rInfo.Listener.end() ;
326 ++pIt2 )
328 IStorageListener* pListener = *pIt2;
329 if (pListener)
330 pListener->changesOccurred(sNormedPath);
333 aReadLock.unlock();
334 // <- SAFE ------------------------------
337 //-----------------------------------------------
338 void StorageHolder::addStorageListener( IStorageListener* pListener,
339 const OUString& sPath )
341 OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
343 // SAFE -> ------------------------------
344 ReadGuard aReadLock(m_aLock);
346 TPath2StorageInfo::iterator pIt1 = m_lStorages.find(sNormedPath);
347 if (pIt1 == m_lStorages.end())
348 return;
350 TStorageInfo& rInfo = pIt1->second;
351 TStorageListenerList::iterator pIt2 = ::std::find(rInfo.Listener.begin(), rInfo.Listener.end(), pListener);
352 if (pIt2 == rInfo.Listener.end())
353 rInfo.Listener.push_back(pListener);
355 aReadLock.unlock();
356 // <- SAFE ------------------------------
359 //-----------------------------------------------
360 void StorageHolder::removeStorageListener( IStorageListener* pListener,
361 const OUString& sPath )
363 OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
365 // SAFE -> ------------------------------
366 ReadGuard aReadLock(m_aLock);
368 TPath2StorageInfo::iterator pIt1 = m_lStorages.find(sNormedPath);
369 if (pIt1 == m_lStorages.end())
370 return;
372 TStorageInfo& rInfo = pIt1->second;
373 TStorageListenerList::iterator pIt2 = ::std::find(rInfo.Listener.begin(), rInfo.Listener.end(), pListener);
374 if (pIt2 != rInfo.Listener.end())
375 rInfo.Listener.erase(pIt2);
377 aReadLock.unlock();
378 // <- SAFE ------------------------------
381 //-----------------------------------------------
382 OUString StorageHolder::getPathOfStorage(const css::uno::Reference< css::embed::XStorage >& xStorage)
384 // SAFE -> ------------------------------
385 ReadGuard aReadLock(m_aLock);
387 TPath2StorageInfo::const_iterator pIt;
388 for ( pIt = m_lStorages.begin();
389 pIt != m_lStorages.end() ;
390 ++pIt )
392 const TStorageInfo& rInfo = pIt->second;
393 if (rInfo.Storage == xStorage)
394 break;
397 if (pIt == m_lStorages.end())
398 return OUString();
400 return pIt->first;
402 // <- SAFE ------------------------------
405 //-----------------------------------------------
406 css::uno::Reference< css::embed::XStorage > StorageHolder::getParentStorage(const css::uno::Reference< css::embed::XStorage >& xChild)
408 OUString sChildPath = getPathOfStorage(xChild);
409 return getParentStorage(sChildPath);
412 //-----------------------------------------------
413 css::uno::Reference< css::embed::XStorage > StorageHolder::getParentStorage(const OUString& sChildPath)
415 // normed path = "a/b/c/" ... we search for "a/b/"
416 OUString sNormedPath = StorageHolder::impl_st_normPath(sChildPath);
417 OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath);
418 sal_Int32 c = lFolders.size();
420 // a) "" => - => no parent
421 // b) "a/b/c/" => "a/b/" => return storage "a/b/"
422 // c) "a/" => "" => return root !
424 // a)
425 if (c < 1)
426 return css::uno::Reference< css::embed::XStorage >();
428 // SAFE -> ----------------------------------
429 ReadGuard aReadLock(m_aLock);
431 // b)
432 if (c < 2)
433 return m_xRoot;
435 // c)
436 OUString sParentPath;
437 sal_Int32 i = 0;
438 for (i=0; i<c-1; ++i)
440 sParentPath += lFolders[i];
441 sParentPath += PATH_SEPARATOR;
444 TPath2StorageInfo::const_iterator pParent = m_lStorages.find(sParentPath);
445 if (pParent != m_lStorages.end())
446 return pParent->second.Storage;
448 aReadLock.unlock();
449 // <- SAFE ----------------------------------
451 // ?
452 LOG_WARNING("StorageHolder::getParentStorage()", "Unexpected situation. Cached storage item seems to be wrong.")
453 return css::uno::Reference< css::embed::XStorage >();
456 //-----------------------------------------------
457 void StorageHolder::operator=(const StorageHolder& rCopy)
459 // SAFE -> ----------------------------------
460 WriteGuard aWriteLock(m_aLock);
462 m_xRoot = rCopy.m_xRoot;
463 m_lStorages = rCopy.m_lStorages;
465 aWriteLock.unlock();
466 // <- SAFE ----------------------------------
469 //-----------------------------------------------
470 css::uno::Reference< css::embed::XStorage > StorageHolder::openSubStorageWithFallback(const css::uno::Reference< css::embed::XStorage >& xBaseStorage ,
471 const OUString& sSubStorage ,
472 sal_Int32 eOpenMode ,
473 sal_Bool bAllowFallback)
475 // a) try it first with user specified open mode
476 // ignore errors ... but save it for later use!
477 css::uno::Exception exResult;
480 css::uno::Reference< css::embed::XStorage > xSubStorage = xBaseStorage->openStorageElement(sSubStorage, eOpenMode);
481 if (xSubStorage.is())
482 return xSubStorage;
484 catch(const css::uno::RuntimeException&)
485 { throw; }
486 catch(const css::uno::Exception& ex)
487 { exResult = ex; }
489 // b) readonly already tried? => forward last error!
490 if (
491 (!bAllowFallback ) || // fallback allowed ?
492 ((eOpenMode & css::embed::ElementModes::WRITE) != css::embed::ElementModes::WRITE) // fallback possible ?
494 throw exResult;
496 // c) try it readonly
497 // dont catch exception here! Outside code whish to know, if operation failed or not.
498 // Otherwhise they work on NULL references ...
499 sal_Int32 eNewMode = (eOpenMode & ~css::embed::ElementModes::WRITE);
500 css::uno::Reference< css::embed::XStorage > xSubStorage = xBaseStorage->openStorageElement(sSubStorage, eNewMode);
501 if (xSubStorage.is())
502 return xSubStorage;
504 // d) no chance!
505 LOG_WARNING("openSubStorageWithFallback()", "Unexpected situation! Got no exception for missing storage ...")
506 return css::uno::Reference< css::embed::XStorage >();
509 //-----------------------------------------------
510 css::uno::Reference< css::io::XStream > StorageHolder::openSubStreamWithFallback(const css::uno::Reference< css::embed::XStorage >& xBaseStorage ,
511 const OUString& sSubStream ,
512 sal_Int32 eOpenMode ,
513 sal_Bool bAllowFallback)
515 // a) try it first with user specified open mode
516 // ignore errors ... but save it for later use!
517 css::uno::Exception exResult;
520 css::uno::Reference< css::io::XStream > xSubStream = xBaseStorage->openStreamElement(sSubStream, eOpenMode);
521 if (xSubStream.is())
522 return xSubStream;
524 catch(const css::uno::RuntimeException&)
525 { throw; }
526 catch(const css::uno::Exception& ex)
527 { exResult = ex; }
529 // b) readonly already tried? => forward last error!
530 if (
531 (!bAllowFallback ) || // fallback allowed ?
532 ((eOpenMode & css::embed::ElementModes::WRITE) != css::embed::ElementModes::WRITE) // fallback possible ?
534 throw exResult;
536 // c) try it readonly
537 // dont catch exception here! Outside code whish to know, if operation failed or not.
538 // Otherwhise they work on NULL references ...
539 sal_Int32 eNewMode = (eOpenMode & ~css::embed::ElementModes::WRITE);
540 css::uno::Reference< css::io::XStream > xSubStream = xBaseStorage->openStreamElement(sSubStream, eNewMode);
541 if (xSubStream.is())
542 return xSubStream;
544 // d) no chance!
545 LOG_WARNING("openSubStreamWithFallbacks()", "Unexpected situation! Got no exception for missing stream ...")
546 return css::uno::Reference< css::io::XStream >();
549 //-----------------------------------------------
550 OUString StorageHolder::impl_st_normPath(const OUString& sPath)
552 // path must start without "/" but end with "/"!
554 OUString sNormedPath = sPath;
556 // "/bla" => "bla" && "/" => "" (!)
557 if (sNormedPath.indexOf(PATH_SEPARATOR) == 0)
558 sNormedPath += sNormedPath.copy(1);
560 // "/" => "" || "" => "" ?
561 if (sNormedPath.isEmpty())
562 return OUString();
564 // "bla" => "bla/"
565 if (sNormedPath.lastIndexOf(PATH_SEPARATOR) != (sNormedPath.getLength()-1))
566 sNormedPath += PATH_SEPARATOR;
568 return sNormedPath;
571 //-----------------------------------------------
572 OUStringList StorageHolder::impl_st_parsePath(const OUString& sPath)
574 OUStringList lToken;
575 sal_Int32 i = 0;
576 while (true)
578 OUString sToken = sPath.getToken(0, PATH_SEPARATOR_UNICODE, i);
579 if (i < 0)
580 break;
581 lToken.push_back(sToken);
583 return lToken;
586 //===============================================
587 } // namespace framework
589 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */