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 #include <accelerators/storageholder.hxx> 27 28 //=============================================== 29 // own includes 30 #include <threadhelp/readguard.hxx> 31 #include <threadhelp/writeguard.hxx> 32 #include <services.h> 33 34 //=============================================== 35 // interface includes 36 37 #ifndef __COM_SUN_STAR_CONTAINER_NOSUCHELEMENTEXCEPTION_HPP_ 38 #include <com/sun/star/container/NoSuchElementException.hpp> 39 #endif 40 41 #ifndef __COM_SUN_STAR_CONTAINER_XNAMEACCESS_HPP_ 42 #include <com/sun/star/container/XNameAccess.hpp> 43 #endif 44 45 #ifndef __COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_ 46 #include <com/sun/star/beans/XPropertySet.hpp> 47 #endif 48 49 #ifndef __COM_SUN_STAR_EMBED_ELEMENTMODES_HPP_ 50 #include <com/sun/star/embed/ElementModes.hpp> 51 #endif 52 53 #ifndef __COM_SUN_STAR_EMBED_XTRANSACTEDOBJECT_HPP_ 54 #include <com/sun/star/embed/XTransactedObject.hpp> 55 #endif 56 57 #ifndef __COM_SUN_STAR_EMBED_XPACKAGESTRUCTURECREATOR_HPP_ 58 #include <com/sun/star/embed/XPackageStructureCreator.hpp> 59 #endif 60 61 #ifndef __COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_ 62 #include <com/sun/star/lang/XSingleServiceFactory.hpp> 63 #endif 64 65 #ifndef __COM_SUN_STAR_IO_XSEEKABLE_HPP_ 66 #include <com/sun/star/io/XSeekable.hpp> 67 #endif 68 69 //=============================================== 70 // other includes 71 #include <comphelper/processfactory.hxx> 72 73 //=============================================== 74 // const 75 76 #define PATH_SEPERATOR_ASCII "/" 77 #define PATH_SEPERATOR_UNICODE ((sal_Unicode)'/') 78 #define PATH_SEPERATOR ::rtl::OUString::createFromAscii(PATH_SEPERATOR_ASCII) 79 80 //=============================================== 81 // namespace 82 83 namespace framework 84 { 85 86 namespace css = ::com::sun::star; 87 88 //----------------------------------------------- 89 StorageHolder::StorageHolder() 90 : ThreadHelpBase( ) 91 , m_xSMGR (::comphelper::getProcessServiceFactory()) 92 { 93 } 94 95 //----------------------------------------------- 96 StorageHolder::StorageHolder(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR) 97 : ThreadHelpBase( ) 98 , m_xSMGR (xSMGR) 99 { 100 } 101 102 //----------------------------------------------- 103 StorageHolder::~StorageHolder() 104 { 105 // TODO implement me 106 // dispose/clear etcpp. 107 } 108 109 //----------------------------------------------- 110 void StorageHolder::forgetCachedStorages() 111 { 112 // SAFE -> ---------------------------------- 113 WriteGuard aWriteLock(m_aLock); 114 115 TPath2StorageInfo::iterator pIt; 116 for ( pIt = m_lStorages.begin(); 117 pIt != m_lStorages.end() ; 118 ++pIt ) 119 { 120 TStorageInfo& rInfo = pIt->second; 121 // TODO think about listener ! 122 rInfo.Storage.clear(); 123 } 124 m_lStorages.clear(); 125 126 aWriteLock.unlock(); 127 // <- SAFE ---------------------------------- 128 } 129 130 //----------------------------------------------- 131 void StorageHolder::setRootStorage(const css::uno::Reference< css::embed::XStorage >& xRoot) 132 { 133 // SAFE -> ---------------------------------- 134 WriteGuard aWriteLock(m_aLock); 135 m_xRoot = xRoot; 136 aWriteLock.unlock(); 137 // <- SAFE ---------------------------------- 138 } 139 140 //----------------------------------------------- 141 css::uno::Reference< css::embed::XStorage > StorageHolder::getRootStorage() const 142 { 143 // SAFE -> ---------------------------------- 144 ReadGuard aReadLock(m_aLock); 145 return m_xRoot; 146 // <- SAFE ---------------------------------- 147 } 148 149 //----------------------------------------------- 150 css::uno::Reference< css::embed::XStorage > StorageHolder::openPath(const ::rtl::OUString& sPath , 151 sal_Int32 nOpenMode) 152 { 153 ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(sPath); 154 OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath); 155 156 // SAFE -> ---------------------------------- 157 ReadGuard aReadLock(m_aLock); 158 css::uno::Reference< css::embed::XStorage > xParent = m_xRoot; 159 aReadLock.unlock(); 160 // <- SAFE ---------------------------------- 161 162 css::uno::Reference< css::embed::XStorage > xChild ; 163 ::rtl::OUString sRelPath; 164 OUStringList::const_iterator pIt ; 165 166 for ( pIt = lFolders.begin(); 167 pIt != lFolders.end() ; 168 ++pIt ) 169 { 170 const ::rtl::OUString& sChild = *pIt; 171 ::rtl::OUString sCheckPath (sRelPath); 172 sCheckPath += sChild; 173 sCheckPath += PATH_SEPERATOR; 174 175 // SAFE -> ------------------------------ 176 aReadLock.lock(); 177 178 // If we found an already open storage ... we must increase 179 // its use count. Otherwhise it will may be closed to early :-) 180 TPath2StorageInfo::iterator pCheck = m_lStorages.find(sCheckPath); 181 TStorageInfo* pInfo = 0; 182 if (pCheck != m_lStorages.end()) 183 { 184 pInfo = &(pCheck->second); 185 ++(pInfo->UseCount); 186 xChild = pInfo->Storage; 187 } 188 else 189 { 190 aReadLock.unlock(); 191 // <- SAFE ------------------------------ 192 193 try 194 { 195 xChild = StorageHolder::openSubStorageWithFallback(xParent, sChild, nOpenMode, sal_True); // TODO think about delegating fallback decision to our own calli! 196 } 197 catch(const css::uno::RuntimeException& exRun) 198 { throw exRun; } 199 catch(const css::uno::Exception& exAny) 200 { 201 /* TODO URGENT! 202 in case we found some "already existing storages" on the path before and increased its UseCount ... 203 and now we will get an exception on creating a new sub storage ... 204 we must decrease all UseCounts, which was touched before. Otherwise these storages can't be closed! 205 206 Idea: Using of another structure member "PossibleUseCount" as vector of unique numbers. 207 Every thread use another unique number to identify all "owned candidates". 208 A flush method with the same unique number force increasing of the "UseCount" variable then 209 inside a synchronized block ... 210 */ 211 throw exAny; 212 } 213 214 // SAFE -> ------------------------------ 215 WriteGuard aWriteLock(m_aLock); 216 pInfo = &(m_lStorages[sCheckPath]); 217 pInfo->Storage = xChild; 218 pInfo->UseCount = 1; 219 aWriteLock.unlock(); 220 // <- SAFE ------------------------------ 221 } 222 223 xParent = xChild; 224 sRelPath += sChild; 225 sRelPath += PATH_SEPERATOR; 226 } 227 228 // TODO think about return last storage as working storage ... but dont caching it inside this holder! 229 // => otherwhise the same storage is may be commit more then once. 230 231 return xChild; 232 } 233 234 //----------------------------------------------- 235 StorageHolder::TStorageList StorageHolder::getAllPathStorages(const ::rtl::OUString& sPath) 236 { 237 ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(sPath); 238 OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath); 239 240 StorageHolder::TStorageList lStoragesOfPath; 241 ::rtl::OUString sRelPath ; 242 OUStringList::const_iterator pIt ; 243 244 // SAFE -> ---------------------------------- 245 ReadGuard aReadLock(m_aLock); 246 247 for ( pIt = lFolders.begin(); 248 pIt != lFolders.end() ; 249 ++pIt ) 250 { 251 const ::rtl::OUString& sChild = *pIt; 252 ::rtl::OUString sCheckPath (sRelPath); 253 sCheckPath += sChild; 254 sCheckPath += PATH_SEPERATOR; 255 256 TPath2StorageInfo::iterator pCheck = m_lStorages.find(sCheckPath); 257 if (pCheck == m_lStorages.end()) 258 { 259 // at least one path element was not found 260 // Seems that this path isn't open ... 261 lStoragesOfPath.clear(); 262 return lStoragesOfPath; 263 } 264 265 TStorageInfo& rInfo = pCheck->second; 266 lStoragesOfPath.push_back(rInfo.Storage); 267 268 sRelPath += sChild; 269 sRelPath += PATH_SEPERATOR; 270 } 271 272 aReadLock.unlock(); 273 // <- SAFE ---------------------------------- 274 275 return lStoragesOfPath; 276 } 277 278 //----------------------------------------------- 279 void StorageHolder::commitPath(const ::rtl::OUString& sPath) 280 { 281 StorageHolder::TStorageList lStorages = getAllPathStorages(sPath); 282 283 css::uno::Reference< css::embed::XTransactedObject > xCommit; 284 StorageHolder::TStorageList::reverse_iterator pIt; 285 for ( pIt = lStorages.rbegin(); // order of commit is important ... otherwhise changes are not recognized! 286 pIt != lStorages.rend() ; 287 ++pIt ) 288 { 289 xCommit = css::uno::Reference< css::embed::XTransactedObject >(*pIt, css::uno::UNO_QUERY); 290 if (!xCommit.is()) 291 continue; 292 xCommit->commit(); 293 } 294 295 // SAFE -> ------------------------------ 296 ReadGuard aReadLock(m_aLock); 297 xCommit = css::uno::Reference< css::embed::XTransactedObject >(m_xRoot, css::uno::UNO_QUERY); 298 aReadLock.unlock(); 299 // <- SAFE ------------------------------ 300 301 if (xCommit.is()) 302 xCommit->commit(); 303 } 304 305 //----------------------------------------------- 306 void StorageHolder::closePath(const ::rtl::OUString& rPath) 307 { 308 ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(rPath); 309 OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath); 310 311 /* convert list of paths in the following way: 312 [0] = "path_1" => "path_1 313 [1] = "path_2" => "path_1/path_2" 314 [2] = "path_3" => "path_1/path_2/path_3" 315 */ 316 OUStringList::iterator pIt1 ; 317 ::rtl::OUString sParentPath; 318 for ( pIt1 = lFolders.begin(); 319 pIt1 != lFolders.end() ; 320 ++pIt1 ) 321 { 322 ::rtl::OUString sCurrentRelPath = sParentPath; 323 sCurrentRelPath += *pIt1; 324 sCurrentRelPath += PATH_SEPERATOR; 325 *pIt1 = sCurrentRelPath; 326 sParentPath = sCurrentRelPath; 327 } 328 329 // SAFE -> ------------------------------ 330 ReadGuard aReadLock(m_aLock); 331 332 OUStringList::reverse_iterator pIt2; 333 for ( pIt2 = lFolders.rbegin(); 334 pIt2 != lFolders.rend() ; 335 ++pIt2 ) 336 { 337 ::rtl::OUString sPath = *pIt2; 338 TPath2StorageInfo::iterator pPath = m_lStorages.find(sPath); 339 if (pPath == m_lStorages.end()) 340 continue; // ??? 341 342 TStorageInfo& rInfo = pPath->second; 343 --rInfo.UseCount; 344 if (rInfo.UseCount < 1) 345 { 346 rInfo.Storage.clear(); 347 m_lStorages.erase(pPath); 348 } 349 } 350 351 aReadLock.unlock(); 352 // <- SAFE ------------------------------ 353 } 354 355 //----------------------------------------------- 356 void StorageHolder::notifyPath(const ::rtl::OUString& sPath) 357 { 358 ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(sPath); 359 360 // SAFE -> ------------------------------ 361 ReadGuard aReadLock(m_aLock); 362 363 TPath2StorageInfo::iterator pIt1 = m_lStorages.find(sNormedPath); 364 if (pIt1 == m_lStorages.end()) 365 return; 366 367 TStorageInfo& rInfo = pIt1->second; 368 TStorageListenerList::iterator pIt2; 369 for ( pIt2 = rInfo.Listener.begin(); 370 pIt2 != rInfo.Listener.end() ; 371 ++pIt2 ) 372 { 373 IStorageListener* pListener = *pIt2; 374 if (pListener) 375 pListener->changesOccured(sNormedPath); 376 } 377 378 aReadLock.unlock(); 379 // <- SAFE ------------------------------ 380 } 381 382 //----------------------------------------------- 383 void StorageHolder::addStorageListener( IStorageListener* pListener, 384 const ::rtl::OUString& sPath ) 385 { 386 ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(sPath); 387 388 // SAFE -> ------------------------------ 389 ReadGuard aReadLock(m_aLock); 390 391 TPath2StorageInfo::iterator pIt1 = m_lStorages.find(sNormedPath); 392 if (pIt1 == m_lStorages.end()) 393 return; 394 395 TStorageInfo& rInfo = pIt1->second; 396 TStorageListenerList::iterator pIt2 = ::std::find(rInfo.Listener.begin(), rInfo.Listener.end(), pListener); 397 if (pIt2 == rInfo.Listener.end()) 398 rInfo.Listener.push_back(pListener); 399 400 aReadLock.unlock(); 401 // <- SAFE ------------------------------ 402 } 403 404 //----------------------------------------------- 405 void StorageHolder::removeStorageListener( IStorageListener* pListener, 406 const ::rtl::OUString& sPath ) 407 { 408 ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(sPath); 409 410 // SAFE -> ------------------------------ 411 ReadGuard aReadLock(m_aLock); 412 413 TPath2StorageInfo::iterator pIt1 = m_lStorages.find(sNormedPath); 414 if (pIt1 == m_lStorages.end()) 415 return; 416 417 TStorageInfo& rInfo = pIt1->second; 418 TStorageListenerList::iterator pIt2 = ::std::find(rInfo.Listener.begin(), rInfo.Listener.end(), pListener); 419 if (pIt2 != rInfo.Listener.end()) 420 rInfo.Listener.erase(pIt2); 421 422 aReadLock.unlock(); 423 // <- SAFE ------------------------------ 424 } 425 426 //----------------------------------------------- 427 ::rtl::OUString StorageHolder::getPathOfStorage(const css::uno::Reference< css::embed::XStorage >& xStorage) 428 { 429 // SAFE -> ------------------------------ 430 ReadGuard aReadLock(m_aLock); 431 432 TPath2StorageInfo::const_iterator pIt; 433 for ( pIt = m_lStorages.begin(); 434 pIt != m_lStorages.end() ; 435 ++pIt ) 436 { 437 const TStorageInfo& rInfo = pIt->second; 438 if (rInfo.Storage == xStorage) 439 break; 440 } 441 442 if (pIt == m_lStorages.end()) 443 return ::rtl::OUString(); 444 445 return pIt->first; 446 447 // <- SAFE ------------------------------ 448 } 449 450 //----------------------------------------------- 451 css::uno::Reference< css::embed::XStorage > StorageHolder::getParentStorage(const css::uno::Reference< css::embed::XStorage >& xChild) 452 { 453 ::rtl::OUString sChildPath = getPathOfStorage(xChild); 454 return getParentStorage(sChildPath); 455 } 456 457 //----------------------------------------------- 458 css::uno::Reference< css::embed::XStorage > StorageHolder::getParentStorage(const ::rtl::OUString& sChildPath) 459 { 460 // normed path = "a/b/c/" ... we search for "a/b/" 461 ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(sChildPath); 462 OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath); 463 sal_Int32 c = lFolders.size(); 464 465 // a) "" => - => no parent 466 // b) "a/b/c/" => "a/b/" => return storage "a/b/" 467 // c) "a/" => "" => return root ! 468 469 // a) 470 if (c < 1) 471 return css::uno::Reference< css::embed::XStorage >(); 472 473 // SAFE -> ---------------------------------- 474 ReadGuard aReadLock(m_aLock); 475 476 // b) 477 if (c < 2) 478 return m_xRoot; 479 480 // c) 481 ::rtl::OUString sParentPath; 482 sal_Int32 i = 0; 483 for (i=0; i<c-1; ++i) 484 { 485 sParentPath += lFolders[i]; 486 sParentPath += PATH_SEPERATOR; 487 } 488 489 TPath2StorageInfo::const_iterator pParent = m_lStorages.find(sParentPath); 490 if (pParent != m_lStorages.end()) 491 return pParent->second.Storage; 492 493 aReadLock.unlock(); 494 // <- SAFE ---------------------------------- 495 496 // ? 497 LOG_WARNING("StorageHolder::getParentStorage()", "Unexpected situation. Cached storage item seems to be wrong.") 498 return css::uno::Reference< css::embed::XStorage >(); 499 } 500 501 //----------------------------------------------- 502 void StorageHolder::operator=(const StorageHolder& rCopy) 503 { 504 // SAFE -> ---------------------------------- 505 WriteGuard aWriteLock(m_aLock); 506 507 m_xSMGR = rCopy.m_xSMGR; // ??? 508 m_xRoot = rCopy.m_xRoot; 509 m_lStorages = rCopy.m_lStorages; 510 511 aWriteLock.unlock(); 512 // <- SAFE ---------------------------------- 513 } 514 515 //----------------------------------------------- 516 css::uno::Reference< css::embed::XStorage > StorageHolder::openSubStorageWithFallback(const css::uno::Reference< css::embed::XStorage >& xBaseStorage , 517 const ::rtl::OUString& sSubStorage , 518 sal_Int32 eOpenMode , 519 sal_Bool bAllowFallback) 520 { 521 // a) try it first with user specified open mode 522 // ignore errors ... but save it for later use! 523 css::uno::Exception exResult; 524 try 525 { 526 css::uno::Reference< css::embed::XStorage > xSubStorage = xBaseStorage->openStorageElement(sSubStorage, eOpenMode); 527 if (xSubStorage.is()) 528 return xSubStorage; 529 } 530 catch(const css::uno::RuntimeException&) 531 { throw; } 532 catch(const css::uno::Exception& ex) 533 { exResult = ex; } 534 535 // b) readonly already tried? => forward last error! 536 if ( 537 (!bAllowFallback ) || // fallback allowed ? 538 ((eOpenMode & css::embed::ElementModes::WRITE) != css::embed::ElementModes::WRITE) // fallback possible ? 539 ) 540 throw exResult; 541 542 // c) try it readonly 543 // dont catch exception here! Outside code whish to know, if operation failed or not. 544 // Otherwhise they work on NULL references ... 545 sal_Int32 eNewMode = (eOpenMode & ~css::embed::ElementModes::WRITE); 546 css::uno::Reference< css::embed::XStorage > xSubStorage = xBaseStorage->openStorageElement(sSubStorage, eNewMode); 547 if (xSubStorage.is()) 548 return xSubStorage; 549 550 // d) no chance! 551 LOG_WARNING("openSubStorageWithFallback()", "Unexpected situation! Got no exception for missing storage ...") 552 return css::uno::Reference< css::embed::XStorage >(); 553 } 554 555 //----------------------------------------------- 556 css::uno::Reference< css::io::XStream > StorageHolder::openSubStreamWithFallback(const css::uno::Reference< css::embed::XStorage >& xBaseStorage , 557 const ::rtl::OUString& sSubStream , 558 sal_Int32 eOpenMode , 559 sal_Bool bAllowFallback) 560 { 561 // a) try it first with user specified open mode 562 // ignore errors ... but save it for later use! 563 css::uno::Exception exResult; 564 try 565 { 566 css::uno::Reference< css::io::XStream > xSubStream = xBaseStorage->openStreamElement(sSubStream, eOpenMode); 567 if (xSubStream.is()) 568 return xSubStream; 569 } 570 catch(const css::uno::RuntimeException&) 571 { throw; } 572 catch(const css::uno::Exception& ex) 573 { exResult = ex; } 574 575 // b) readonly already tried? => forward last error! 576 if ( 577 (!bAllowFallback ) || // fallback allowed ? 578 ((eOpenMode & css::embed::ElementModes::WRITE) != css::embed::ElementModes::WRITE) // fallback possible ? 579 ) 580 throw exResult; 581 582 // c) try it readonly 583 // dont catch exception here! Outside code whish to know, if operation failed or not. 584 // Otherwhise they work on NULL references ... 585 sal_Int32 eNewMode = (eOpenMode & ~css::embed::ElementModes::WRITE); 586 css::uno::Reference< css::io::XStream > xSubStream = xBaseStorage->openStreamElement(sSubStream, eNewMode); 587 if (xSubStream.is()) 588 return xSubStream; 589 590 // d) no chance! 591 LOG_WARNING("openSubStreamWithFallbacks()", "Unexpected situation! Got no exception for missing stream ...") 592 return css::uno::Reference< css::io::XStream >(); 593 } 594 595 //----------------------------------------------- 596 ::rtl::OUString StorageHolder::impl_st_normPath(const ::rtl::OUString& sPath) 597 { 598 // path must start without "/" but end with "/"! 599 600 ::rtl::OUString sNormedPath = sPath; 601 602 // "/bla" => "bla" && "/" => "" (!) 603 if (sNormedPath.indexOf(PATH_SEPERATOR) == 0) 604 sNormedPath += sNormedPath.copy(1); 605 606 // "/" => "" || "" => "" ? 607 if (sNormedPath.getLength() < 1) 608 return ::rtl::OUString(); 609 610 // "bla" => "bla/" 611 if (sNormedPath.lastIndexOf(PATH_SEPERATOR) != (sNormedPath.getLength()-1)) 612 sNormedPath += PATH_SEPERATOR; 613 614 return sNormedPath; 615 } 616 617 //----------------------------------------------- 618 OUStringList StorageHolder::impl_st_parsePath(const ::rtl::OUString& sPath) 619 { 620 OUStringList lToken; 621 sal_Int32 i = 0; 622 while (sal_True) 623 { 624 ::rtl::OUString sToken = sPath.getToken(0, PATH_SEPERATOR_UNICODE, i); 625 if (i < 0) 626 break; 627 lToken.push_back(sToken); 628 } 629 return lToken; 630 } 631 632 //=============================================== 633 } // namespace framework 634