1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: storageholder.cxx,v $
10 * $Revision: 1.8.82.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_framework.hxx"
33 #include <accelerators/storageholder.hxx>
35 //===============================================
37 #include <threadhelp/readguard.hxx>
38 #include <threadhelp/writeguard.hxx>
41 //===============================================
44 #ifndef __COM_SUN_STAR_CONTAINER_NOSUCHELEMENTEXCEPTION_HPP_
45 #include <com/sun/star/container/NoSuchElementException.hpp>
48 #ifndef __COM_SUN_STAR_CONTAINER_XNAMEACCESS_HPP_
49 #include <com/sun/star/container/XNameAccess.hpp>
52 #ifndef __COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
53 #include <com/sun/star/beans/XPropertySet.hpp>
56 #ifndef __COM_SUN_STAR_EMBED_ELEMENTMODES_HPP_
57 #include <com/sun/star/embed/ElementModes.hpp>
60 #ifndef __COM_SUN_STAR_EMBED_XTRANSACTEDOBJECT_HPP_
61 #include <com/sun/star/embed/XTransactedObject.hpp>
64 #ifndef __COM_SUN_STAR_EMBED_XPACKAGESTRUCTURECREATOR_HPP_
65 #include <com/sun/star/embed/XPackageStructureCreator.hpp>
68 #ifndef __COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_
69 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
72 #ifndef __COM_SUN_STAR_IO_XSEEKABLE_HPP_
73 #include <com/sun/star/io/XSeekable.hpp>
76 //===============================================
78 #include <comphelper/processfactory.hxx>
80 //===============================================
83 #define PATH_SEPERATOR_ASCII "/"
84 #define PATH_SEPERATOR_UNICODE ((sal_Unicode)'/')
85 #define PATH_SEPERATOR ::rtl::OUString::createFromAscii(PATH_SEPERATOR_ASCII)
87 //===============================================
93 namespace css
= ::com::sun::star
;
95 //-----------------------------------------------
96 StorageHolder::StorageHolder()
98 , m_xSMGR (::comphelper::getProcessServiceFactory())
102 //-----------------------------------------------
103 StorageHolder::StorageHolder(const css::uno::Reference
< css::lang::XMultiServiceFactory
>& xSMGR
)
109 //-----------------------------------------------
110 StorageHolder::~StorageHolder()
113 // dispose/clear etcpp.
116 //-----------------------------------------------
117 void StorageHolder::forgetCachedStorages()
119 // SAFE -> ----------------------------------
120 WriteGuard
aWriteLock(m_aLock
);
122 TPath2StorageInfo::iterator pIt
;
123 for ( pIt
= m_lStorages
.begin();
124 pIt
!= m_lStorages
.end() ;
127 TStorageInfo
& rInfo
= pIt
->second
;
128 // TODO think about listener !
129 rInfo
.Storage
.clear();
134 // <- SAFE ----------------------------------
137 //-----------------------------------------------
138 void StorageHolder::setRootStorage(const css::uno::Reference
< css::embed::XStorage
>& xRoot
)
140 // SAFE -> ----------------------------------
141 WriteGuard
aWriteLock(m_aLock
);
144 // <- SAFE ----------------------------------
147 //-----------------------------------------------
148 css::uno::Reference
< css::embed::XStorage
> StorageHolder::getRootStorage() const
150 // SAFE -> ----------------------------------
151 ReadGuard
aReadLock(m_aLock
);
153 // <- SAFE ----------------------------------
156 //-----------------------------------------------
157 css::uno::Reference
< css::embed::XStorage
> StorageHolder::openPath(const ::rtl::OUString
& sPath
,
160 ::rtl::OUString sNormedPath
= StorageHolder::impl_st_normPath(sPath
);
161 OUStringList lFolders
= StorageHolder::impl_st_parsePath(sNormedPath
);
163 // SAFE -> ----------------------------------
164 ReadGuard
aReadLock(m_aLock
);
165 css::uno::Reference
< css::embed::XStorage
> xParent
= m_xRoot
;
167 // <- SAFE ----------------------------------
169 css::uno::Reference
< css::embed::XStorage
> xChild
;
170 ::rtl::OUString sRelPath
;
171 OUStringList::const_iterator pIt
;
173 for ( pIt
= lFolders
.begin();
174 pIt
!= lFolders
.end() ;
177 const ::rtl::OUString
& sChild
= *pIt
;
178 ::rtl::OUString
sCheckPath (sRelPath
);
179 sCheckPath
+= sChild
;
180 sCheckPath
+= PATH_SEPERATOR
;
182 // SAFE -> ------------------------------
185 // If we found an already open storage ... we must increase
186 // its use count. Otherwhise it will may be closed to early :-)
187 TPath2StorageInfo::iterator pCheck
= m_lStorages
.find(sCheckPath
);
188 TStorageInfo
* pInfo
= 0;
189 if (pCheck
!= m_lStorages
.end())
191 pInfo
= &(pCheck
->second
);
193 xChild
= pInfo
->Storage
;
198 // <- SAFE ------------------------------
202 xChild
= StorageHolder::openSubStorageWithFallback(xParent
, sChild
, nOpenMode
, sal_True
); // TODO think about delegating fallback decision to our own calli!
204 catch(const css::uno::RuntimeException
& exRun
)
206 catch(const css::uno::Exception
& exAny
)
209 in case we found some "already existing storages" on the path before and increased its UseCount ...
210 and now we will get an exception on creating a new sub storage ...
211 we must decrease all UseCounts, which was touched before. Otherwise these storages cant be closed!
213 Idea: Using of another structure member "PossibleUseCount" as vector of unique numbers.
214 Every thread use another unique number to identify all "owned candidates".
215 A flush method with the same unique number force increasing of the "UseCount" variable then
216 inside a synchronized block ...
221 // SAFE -> ------------------------------
222 WriteGuard
aWriteLock(m_aLock
);
223 pInfo
= &(m_lStorages
[sCheckPath
]);
224 pInfo
->Storage
= xChild
;
227 // <- SAFE ------------------------------
232 sRelPath
+= PATH_SEPERATOR
;
235 // TODO think about return last storage as working storage ... but dont caching it inside this holder!
236 // => otherwhise the same storage is may be commit more then once.
241 //-----------------------------------------------
242 StorageHolder::TStorageList
StorageHolder::getAllPathStorages(const ::rtl::OUString
& sPath
)
244 ::rtl::OUString sNormedPath
= StorageHolder::impl_st_normPath(sPath
);
245 OUStringList lFolders
= StorageHolder::impl_st_parsePath(sNormedPath
);
247 StorageHolder::TStorageList lStoragesOfPath
;
248 ::rtl::OUString sRelPath
;
249 OUStringList::const_iterator pIt
;
251 // SAFE -> ----------------------------------
252 ReadGuard
aReadLock(m_aLock
);
254 for ( pIt
= lFolders
.begin();
255 pIt
!= lFolders
.end() ;
258 const ::rtl::OUString
& sChild
= *pIt
;
259 ::rtl::OUString
sCheckPath (sRelPath
);
260 sCheckPath
+= sChild
;
261 sCheckPath
+= PATH_SEPERATOR
;
263 TPath2StorageInfo::iterator pCheck
= m_lStorages
.find(sCheckPath
);
264 if (pCheck
== m_lStorages
.end())
266 // at least one path element was not found
267 // Seems that this path isnt open ...
268 lStoragesOfPath
.clear();
269 return lStoragesOfPath
;
272 TStorageInfo
& rInfo
= pCheck
->second
;
273 lStoragesOfPath
.push_back(rInfo
.Storage
);
276 sRelPath
+= PATH_SEPERATOR
;
280 // <- SAFE ----------------------------------
282 return lStoragesOfPath
;
285 //-----------------------------------------------
286 void StorageHolder::commitPath(const ::rtl::OUString
& sPath
)
288 StorageHolder::TStorageList lStorages
= getAllPathStorages(sPath
);
290 css::uno::Reference
< css::embed::XTransactedObject
> xCommit
;
291 StorageHolder::TStorageList::reverse_iterator pIt
;
292 for ( pIt
= lStorages
.rbegin(); // order of commit is important ... otherwhise changes are not recognized!
293 pIt
!= lStorages
.rend() ;
296 xCommit
= css::uno::Reference
< css::embed::XTransactedObject
>(*pIt
, css::uno::UNO_QUERY
);
302 // SAFE -> ------------------------------
303 ReadGuard
aReadLock(m_aLock
);
304 xCommit
= css::uno::Reference
< css::embed::XTransactedObject
>(m_xRoot
, css::uno::UNO_QUERY
);
306 // <- SAFE ------------------------------
312 //-----------------------------------------------
313 void StorageHolder::closePath(const ::rtl::OUString
& rPath
)
315 ::rtl::OUString sNormedPath
= StorageHolder::impl_st_normPath(rPath
);
316 OUStringList lFolders
= StorageHolder::impl_st_parsePath(sNormedPath
);
318 /* convert list of pathes in the following way:
319 [0] = "path_1" => "path_1
320 [1] = "path_2" => "path_1/path_2"
321 [2] = "path_3" => "path_1/path_2/path_3"
323 OUStringList::iterator pIt1
;
324 ::rtl::OUString sParentPath
;
325 for ( pIt1
= lFolders
.begin();
326 pIt1
!= lFolders
.end() ;
329 ::rtl::OUString sCurrentRelPath
= sParentPath
;
330 sCurrentRelPath
+= *pIt1
;
331 sCurrentRelPath
+= PATH_SEPERATOR
;
332 *pIt1
= sCurrentRelPath
;
333 sParentPath
= sCurrentRelPath
;
336 // SAFE -> ------------------------------
337 ReadGuard
aReadLock(m_aLock
);
339 OUStringList::reverse_iterator pIt2
;
340 for ( pIt2
= lFolders
.rbegin();
341 pIt2
!= lFolders
.rend() ;
344 ::rtl::OUString sPath
= *pIt2
;
345 TPath2StorageInfo::iterator pPath
= m_lStorages
.find(sPath
);
346 if (pPath
== m_lStorages
.end())
349 TStorageInfo
& rInfo
= pPath
->second
;
351 if (rInfo
.UseCount
< 1)
353 rInfo
.Storage
.clear();
354 m_lStorages
.erase(pPath
);
359 // <- SAFE ------------------------------
362 //-----------------------------------------------
363 void StorageHolder::notifyPath(const ::rtl::OUString
& sPath
)
365 ::rtl::OUString sNormedPath
= StorageHolder::impl_st_normPath(sPath
);
367 // SAFE -> ------------------------------
368 ReadGuard
aReadLock(m_aLock
);
370 TPath2StorageInfo::iterator pIt1
= m_lStorages
.find(sNormedPath
);
371 if (pIt1
== m_lStorages
.end())
374 TStorageInfo
& rInfo
= pIt1
->second
;
375 TStorageListenerList::iterator pIt2
;
376 for ( pIt2
= rInfo
.Listener
.begin();
377 pIt2
!= rInfo
.Listener
.end() ;
380 IStorageListener
* pListener
= *pIt2
;
382 pListener
->changesOccured(sNormedPath
);
386 // <- SAFE ------------------------------
389 //-----------------------------------------------
390 void StorageHolder::addStorageListener( IStorageListener
* pListener
,
391 const ::rtl::OUString
& sPath
)
393 ::rtl::OUString sNormedPath
= StorageHolder::impl_st_normPath(sPath
);
395 // SAFE -> ------------------------------
396 ReadGuard
aReadLock(m_aLock
);
398 TPath2StorageInfo::iterator pIt1
= m_lStorages
.find(sNormedPath
);
399 if (pIt1
== m_lStorages
.end())
402 TStorageInfo
& rInfo
= pIt1
->second
;
403 TStorageListenerList::iterator pIt2
= ::std::find(rInfo
.Listener
.begin(), rInfo
.Listener
.end(), pListener
);
404 if (pIt2
== rInfo
.Listener
.end())
405 rInfo
.Listener
.push_back(pListener
);
408 // <- SAFE ------------------------------
411 //-----------------------------------------------
412 void StorageHolder::removeStorageListener( IStorageListener
* pListener
,
413 const ::rtl::OUString
& sPath
)
415 ::rtl::OUString sNormedPath
= StorageHolder::impl_st_normPath(sPath
);
417 // SAFE -> ------------------------------
418 ReadGuard
aReadLock(m_aLock
);
420 TPath2StorageInfo::iterator pIt1
= m_lStorages
.find(sNormedPath
);
421 if (pIt1
== m_lStorages
.end())
424 TStorageInfo
& rInfo
= pIt1
->second
;
425 TStorageListenerList::iterator pIt2
= ::std::find(rInfo
.Listener
.begin(), rInfo
.Listener
.end(), pListener
);
426 if (pIt2
!= rInfo
.Listener
.end())
427 rInfo
.Listener
.erase(pIt2
);
430 // <- SAFE ------------------------------
433 //-----------------------------------------------
434 ::rtl::OUString
StorageHolder::getPathOfStorage(const css::uno::Reference
< css::embed::XStorage
>& xStorage
)
436 // SAFE -> ------------------------------
437 ReadGuard
aReadLock(m_aLock
);
439 TPath2StorageInfo::const_iterator pIt
;
440 for ( pIt
= m_lStorages
.begin();
441 pIt
!= m_lStorages
.end() ;
444 const TStorageInfo
& rInfo
= pIt
->second
;
445 if (rInfo
.Storage
== xStorage
)
449 if (pIt
== m_lStorages
.end())
450 return ::rtl::OUString();
454 // <- SAFE ------------------------------
457 //-----------------------------------------------
458 css::uno::Reference
< css::embed::XStorage
> StorageHolder::getParentStorage(const css::uno::Reference
< css::embed::XStorage
>& xChild
)
460 ::rtl::OUString sChildPath
= getPathOfStorage(xChild
);
461 return getParentStorage(sChildPath
);
464 //-----------------------------------------------
465 css::uno::Reference
< css::embed::XStorage
> StorageHolder::getParentStorage(const ::rtl::OUString
& sChildPath
)
467 // normed path = "a/b/c/" ... we search for "a/b/"
468 ::rtl::OUString sNormedPath
= StorageHolder::impl_st_normPath(sChildPath
);
469 OUStringList lFolders
= StorageHolder::impl_st_parsePath(sNormedPath
);
470 sal_Int32 c
= lFolders
.size();
472 // a) "" => - => no parent
473 // b) "a/b/c/" => "a/b/" => return storage "a/b/"
474 // c) "a/" => "" => return root !
478 return css::uno::Reference
< css::embed::XStorage
>();
480 // SAFE -> ----------------------------------
481 ReadGuard
aReadLock(m_aLock
);
488 ::rtl::OUString sParentPath
;
490 for (i
=0; i
<c
-1; ++i
)
492 sParentPath
+= lFolders
[i
];
493 sParentPath
+= PATH_SEPERATOR
;
496 TPath2StorageInfo::const_iterator pParent
= m_lStorages
.find(sParentPath
);
497 if (pParent
!= m_lStorages
.end())
498 return pParent
->second
.Storage
;
501 // <- SAFE ----------------------------------
504 LOG_WARNING("StorageHolder::getParentStorage()", "Unexpected situation. Cached storage item seems to be wrong.")
505 return css::uno::Reference
< css::embed::XStorage
>();
508 //-----------------------------------------------
509 void StorageHolder::operator=(const StorageHolder
& rCopy
)
511 // SAFE -> ----------------------------------
512 WriteGuard
aWriteLock(m_aLock
);
514 m_xSMGR
= rCopy
.m_xSMGR
; // ???
515 m_xRoot
= rCopy
.m_xRoot
;
516 m_lStorages
= rCopy
.m_lStorages
;
519 // <- SAFE ----------------------------------
522 //-----------------------------------------------
523 css::uno::Reference
< css::embed::XStorage
> StorageHolder::openSubStorageWithFallback(const css::uno::Reference
< css::embed::XStorage
>& xBaseStorage
,
524 const ::rtl::OUString
& sSubStorage
,
525 sal_Int32 eOpenMode
,
526 sal_Bool bAllowFallback
)
528 // a) try it first with user specified open mode
529 // ignore errors ... but save it for later use!
530 css::uno::Exception exResult
;
533 css::uno::Reference
< css::embed::XStorage
> xSubStorage
= xBaseStorage
->openStorageElement(sSubStorage
, eOpenMode
);
534 if (xSubStorage
.is())
537 catch(const css::uno::RuntimeException
&)
539 catch(const css::uno::Exception
& ex
)
542 // b) readonly already tried? => forward last error!
544 (!bAllowFallback
) || // fallback allowed ?
545 ((eOpenMode
& css::embed::ElementModes::WRITE
) != css::embed::ElementModes::WRITE
) // fallback possible ?
549 // c) try it readonly
550 // dont catch exception here! Outside code whish to know, if operation failed or not.
551 // Otherwhise they work on NULL references ...
552 sal_Int32 eNewMode
= (eOpenMode
& ~css::embed::ElementModes::WRITE
);
553 css::uno::Reference
< css::embed::XStorage
> xSubStorage
= xBaseStorage
->openStorageElement(sSubStorage
, eNewMode
);
554 if (xSubStorage
.is())
558 LOG_WARNING("openSubStorageWithFallback()", "Unexpected situation! Got no exception for missing storage ...")
559 return css::uno::Reference
< css::embed::XStorage
>();
562 //-----------------------------------------------
563 css::uno::Reference
< css::io::XStream
> StorageHolder::openSubStreamWithFallback(const css::uno::Reference
< css::embed::XStorage
>& xBaseStorage
,
564 const ::rtl::OUString
& sSubStream
,
565 sal_Int32 eOpenMode
,
566 sal_Bool bAllowFallback
)
568 // a) try it first with user specified open mode
569 // ignore errors ... but save it for later use!
570 css::uno::Exception exResult
;
573 css::uno::Reference
< css::io::XStream
> xSubStream
= xBaseStorage
->openStreamElement(sSubStream
, eOpenMode
);
577 catch(const css::uno::RuntimeException
&)
579 catch(const css::uno::Exception
& ex
)
582 // b) readonly already tried? => forward last error!
584 (!bAllowFallback
) || // fallback allowed ?
585 ((eOpenMode
& css::embed::ElementModes::WRITE
) != css::embed::ElementModes::WRITE
) // fallback possible ?
589 // c) try it readonly
590 // dont catch exception here! Outside code whish to know, if operation failed or not.
591 // Otherwhise they work on NULL references ...
592 sal_Int32 eNewMode
= (eOpenMode
& ~css::embed::ElementModes::WRITE
);
593 css::uno::Reference
< css::io::XStream
> xSubStream
= xBaseStorage
->openStreamElement(sSubStream
, eNewMode
);
598 LOG_WARNING("openSubStreamWithFallbacks()", "Unexpected situation! Got no exception for missing stream ...")
599 return css::uno::Reference
< css::io::XStream
>();
602 //-----------------------------------------------
603 ::rtl::OUString
StorageHolder::impl_st_normPath(const ::rtl::OUString
& sPath
)
605 // path must start without "/" but end with "/"!
607 ::rtl::OUString sNormedPath
= sPath
;
609 // "/bla" => "bla" && "/" => "" (!)
610 if (sNormedPath
.indexOf(PATH_SEPERATOR
) == 0)
611 sNormedPath
+= sNormedPath
.copy(1);
613 // "/" => "" || "" => "" ?
614 if (sNormedPath
.getLength() < 1)
615 return ::rtl::OUString();
618 if (sNormedPath
.lastIndexOf(PATH_SEPERATOR
) != (sNormedPath
.getLength()-1))
619 sNormedPath
+= PATH_SEPERATOR
;
624 //-----------------------------------------------
625 OUStringList
StorageHolder::impl_st_parsePath(const ::rtl::OUString
& sPath
)
631 ::rtl::OUString sToken
= sPath
.getToken(0, PATH_SEPERATOR_UNICODE
, i
);
634 lToken
.push_back(sToken
);
639 //===============================================
640 } // namespace framework