1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_ucb.hxx" 30 31 /************************************************************************** 32 TODO 33 ************************************************************************** 34 35 *************************************************************************/ 36 37 #include "rtl/ustrbuf.hxx" 38 39 #include "com/sun/star/container/XNameAccess.hpp" 40 #include "com/sun/star/embed/XStorage.hpp" 41 42 #include "ucbhelper/contentidentifier.hxx" 43 44 #include "tdoc_provider.hxx" 45 #include "tdoc_content.hxx" 46 #include "tdoc_uri.hxx" 47 #include "tdoc_docmgr.hxx" 48 #include "tdoc_storage.hxx" 49 50 using namespace com::sun::star; 51 using namespace tdoc_ucp; 52 53 //========================================================================= 54 //========================================================================= 55 // 56 // ContentProvider Implementation. 57 // 58 //========================================================================= 59 //========================================================================= 60 61 ContentProvider::ContentProvider( 62 const uno::Reference< lang::XMultiServiceFactory >& xSMgr ) 63 : ::ucbhelper::ContentProviderImplHelper( xSMgr ), 64 m_xDocsMgr( new OfficeDocumentsManager( xSMgr, this ) ), 65 m_xStgElemFac( new StorageElementFactory( xSMgr, m_xDocsMgr ) ) 66 { 67 } 68 69 //========================================================================= 70 // virtual 71 ContentProvider::~ContentProvider() 72 { 73 if ( m_xDocsMgr.is() ) 74 m_xDocsMgr->destroy(); 75 } 76 77 //========================================================================= 78 // 79 // XInterface methods. 80 // 81 //========================================================================= 82 83 XINTERFACE_IMPL_4( ContentProvider, 84 lang::XTypeProvider, 85 lang::XServiceInfo, 86 ucb::XContentProvider, 87 frame::XTransientDocumentsDocumentContentFactory ); 88 89 //========================================================================= 90 // 91 // XTypeProvider methods. 92 // 93 //========================================================================= 94 95 XTYPEPROVIDER_IMPL_4( ContentProvider, 96 lang::XTypeProvider, 97 lang::XServiceInfo, 98 ucb::XContentProvider, 99 frame::XTransientDocumentsDocumentContentFactory ); 100 101 //========================================================================= 102 // 103 // XServiceInfo methods. 104 // 105 //========================================================================= 106 107 XSERVICEINFO_IMPL_1( 108 ContentProvider, 109 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 110 "com.sun.star.comp.ucb.TransientDocumentsContentProvider" ) ), 111 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 112 TDOC_CONTENT_PROVIDER_SERVICE_NAME ) ) ); 113 114 //========================================================================= 115 // 116 // Service factory implementation. 117 // 118 //========================================================================= 119 120 ONE_INSTANCE_SERVICE_FACTORY_IMPL( ContentProvider ); 121 122 //========================================================================= 123 // 124 // XContentProvider methods. 125 // 126 //========================================================================= 127 128 // virtual 129 uno::Reference< ucb::XContent > SAL_CALL 130 ContentProvider::queryContent( 131 const uno::Reference< ucb::XContentIdentifier >& Identifier ) 132 throw( ucb::IllegalIdentifierException, uno::RuntimeException ) 133 { 134 Uri aUri( Identifier->getContentIdentifier() ); 135 if ( !aUri.isValid() ) 136 throw ucb::IllegalIdentifierException( 137 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Invalid URL!" ) ), 138 Identifier ); 139 140 // Normalize URI. 141 uno::Reference< ucb::XContentIdentifier > xCanonicId 142 = new ::ucbhelper::ContentIdentifier( m_xSMgr, aUri.getUri() ); 143 144 osl::MutexGuard aGuard( m_aMutex ); 145 146 // Check, if a content with given id already exists... 147 uno::Reference< ucb::XContent > xContent 148 = queryExistingContent( xCanonicId ).get(); 149 150 if ( !xContent.is() ) 151 { 152 // Create a new content. 153 xContent = Content::create( m_xSMgr, this, xCanonicId ); 154 registerNewContent( xContent ); 155 } 156 157 return xContent; 158 } 159 160 //========================================================================= 161 // 162 // XTransientDocumentsDocumentContentFactory methods. 163 // 164 //========================================================================= 165 166 // virtual 167 uno::Reference< ucb::XContent > SAL_CALL 168 ContentProvider::createDocumentContent( 169 const uno::Reference< frame::XModel >& Model ) 170 throw ( lang::IllegalArgumentException, uno::RuntimeException ) 171 { 172 // model -> id -> content identifier -> queryContent 173 if ( m_xDocsMgr.is() ) 174 { 175 rtl::OUString aDocId = m_xDocsMgr->queryDocumentId( Model ); 176 if ( aDocId.getLength() > 0 ) 177 { 178 rtl::OUStringBuffer aBuffer; 179 aBuffer.appendAscii( TDOC_URL_SCHEME ":/" ); 180 aBuffer.append( aDocId ); 181 182 uno::Reference< ucb::XContentIdentifier > xId 183 = new ::ucbhelper::ContentIdentifier( 184 m_xSMgr, aBuffer.makeStringAndClear() ); 185 186 osl::MutexGuard aGuard( m_aMutex ); 187 188 // Check, if a content with given id already exists... 189 uno::Reference< ucb::XContent > xContent 190 = queryExistingContent( xId ).get(); 191 192 if ( !xContent.is() ) 193 { 194 // Create a new content. 195 xContent = Content::create( m_xSMgr, this, xId ); 196 } 197 198 if ( xContent.is() ) 199 return xContent; 200 201 // no content. 202 throw lang::IllegalArgumentException( 203 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 204 "Illegal Content Identifier!" ) ), 205 static_cast< cppu::OWeakObject * >( this ), 206 1 ); 207 } 208 else 209 { 210 throw lang::IllegalArgumentException( 211 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 212 "Unable to obtain document id from model!" ) ), 213 static_cast< cppu::OWeakObject * >( this ), 214 1 ); 215 } 216 } 217 else 218 { 219 throw lang::IllegalArgumentException( 220 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 221 "No Document Manager!" ) ), 222 static_cast< cppu::OWeakObject * >( this ), 223 1 ); 224 } 225 } 226 227 //========================================================================= 228 // 229 // interface OfficeDocumentsEventListener 230 // 231 //========================================================================= 232 233 // virtual 234 void ContentProvider::notifyDocumentClosed( const rtl::OUString & rDocId ) 235 { 236 osl::MutexGuard aGuard( getContentListMutex() ); 237 238 ::ucbhelper::ContentRefList aAllContents; 239 queryExistingContents( aAllContents ); 240 241 ::ucbhelper::ContentRefList::const_iterator it = aAllContents.begin(); 242 ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end(); 243 244 // Notify all content objects related to the closed doc. 245 246 bool bFoundDocumentContent = false; 247 rtl::Reference< Content > xRoot; 248 249 while ( it != end ) 250 { 251 Uri aUri( (*it)->getIdentifier()->getContentIdentifier() ); 252 OSL_ENSURE( aUri.isValid(), 253 "ContentProvider::notifyDocumentClosed - Invalid URI!" ); 254 255 if ( !bFoundDocumentContent ) 256 { 257 if ( aUri.isRoot() ) 258 { 259 xRoot = static_cast< Content * >( (*it).get() ); 260 } 261 else if ( aUri.isDocument() ) 262 { 263 if ( aUri.getDocumentId() == rDocId ) 264 { 265 bFoundDocumentContent = true; 266 267 // document content will notify removal of child itself; 268 // no need for the root to propagate this. 269 xRoot.clear(); 270 } 271 } 272 } 273 274 if ( aUri.getDocumentId() == rDocId ) 275 { 276 // Inform content. 277 rtl::Reference< Content > xContent 278 = static_cast< Content * >( (*it).get() ); 279 280 xContent->notifyDocumentClosed(); 281 } 282 283 ++it; 284 } 285 286 if ( xRoot.is() ) 287 { 288 // No document content found for rDocId but root content 289 // instanciated. Root content must announce document removal 290 // to content event listeners. 291 xRoot->notifyChildRemoved( rDocId ); 292 } 293 } 294 295 //========================================================================= 296 // virtual 297 void ContentProvider::notifyDocumentOpened( const rtl::OUString & rDocId ) 298 { 299 osl::MutexGuard aGuard( getContentListMutex() ); 300 301 ::ucbhelper::ContentRefList aAllContents; 302 queryExistingContents( aAllContents ); 303 304 ::ucbhelper::ContentRefList::const_iterator it = aAllContents.begin(); 305 ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end(); 306 307 // Find root content. If instanciated let it propagate document insertion. 308 309 while ( it != end ) 310 { 311 Uri aUri( (*it)->getIdentifier()->getContentIdentifier() ); 312 OSL_ENSURE( aUri.isValid(), 313 "ContentProvider::notifyDocumentOpened - Invalid URI!" ); 314 315 if ( aUri.isRoot() ) 316 { 317 rtl::Reference< Content > xRoot 318 = static_cast< Content * >( (*it).get() ); 319 xRoot->notifyChildInserted( rDocId ); 320 321 // Done. 322 break; 323 } 324 325 ++it; 326 } 327 } 328 329 //========================================================================= 330 // 331 // Non-UNO 332 // 333 //========================================================================= 334 335 uno::Reference< embed::XStorage > 336 ContentProvider::queryStorage( const rtl::OUString & rUri, 337 StorageAccessMode eMode ) const 338 { 339 if ( m_xStgElemFac.is() ) 340 { 341 try 342 { 343 return m_xStgElemFac->createStorage( rUri, eMode ); 344 } 345 catch ( embed::InvalidStorageException const & ) 346 { 347 OSL_ENSURE( false, "Caught InvalidStorageException!" ); 348 } 349 catch ( lang::IllegalArgumentException const & ) 350 { 351 OSL_ENSURE( false, "Caught IllegalArgumentException!" ); 352 } 353 catch ( io::IOException const & ) 354 { 355 // Okay to happen, for instance when the storage does not exist. 356 //OSL_ENSURE( false, "Caught IOException!" ); 357 } 358 catch ( embed::StorageWrappedTargetException const & ) 359 { 360 OSL_ENSURE( false, "Caught embed::StorageWrappedTargetException!" ); 361 } 362 } 363 return uno::Reference< embed::XStorage >(); 364 } 365 366 //========================================================================= 367 uno::Reference< embed::XStorage > 368 ContentProvider::queryStorageClone( const rtl::OUString & rUri ) const 369 { 370 if ( m_xStgElemFac.is() ) 371 { 372 try 373 { 374 Uri aUri( rUri ); 375 uno::Reference< embed::XStorage > xParentStorage 376 = m_xStgElemFac->createStorage( aUri.getParentUri(), READ ); 377 uno::Reference< embed::XStorage > xStorage 378 = m_xStgElemFac->createTemporaryStorage(); 379 380 xParentStorage->copyStorageElementLastCommitTo( 381 aUri.getDecodedName(), xStorage ); 382 return xStorage; 383 } 384 catch ( embed::InvalidStorageException const & ) 385 { 386 OSL_ENSURE( false, "Caught InvalidStorageException!" ); 387 } 388 catch ( lang::IllegalArgumentException const & ) 389 { 390 OSL_ENSURE( false, "Caught IllegalArgumentException!" ); 391 } 392 catch ( io::IOException const & ) 393 { 394 // Okay to happen, for instance when the storage does not exist. 395 //OSL_ENSURE( false, "Caught IOException!" ); 396 } 397 catch ( embed::StorageWrappedTargetException const & ) 398 { 399 OSL_ENSURE( false, "Caught embed::StorageWrappedTargetException!" ); 400 } 401 } 402 403 return uno::Reference< embed::XStorage >(); 404 } 405 406 //========================================================================= 407 uno::Reference< io::XInputStream > 408 ContentProvider::queryInputStream( const rtl::OUString & rUri, 409 const rtl::OUString & rPassword ) const 410 throw ( packages::WrongPasswordException ) 411 { 412 if ( m_xStgElemFac.is() ) 413 { 414 try 415 { 416 return m_xStgElemFac->createInputStream( rUri, rPassword ); 417 } 418 catch ( embed::InvalidStorageException const & ) 419 { 420 OSL_ENSURE( false, "Caught InvalidStorageException!" ); 421 } 422 catch ( lang::IllegalArgumentException const & ) 423 { 424 OSL_ENSURE( false, "Caught IllegalArgumentException!" ); 425 } 426 catch ( io::IOException const & ) 427 { 428 OSL_ENSURE( false, "Caught IOException!" ); 429 } 430 catch ( embed::StorageWrappedTargetException const & ) 431 { 432 OSL_ENSURE( false, "Caught embed::StorageWrappedTargetException!" ); 433 } 434 // catch ( packages::WrongPasswordException const & ) 435 // { 436 // // the key provided is wrong; rethrow; to be handled by caller. 437 // throw; 438 // } 439 } 440 return uno::Reference< io::XInputStream >(); 441 } 442 443 //========================================================================= 444 uno::Reference< io::XOutputStream > 445 ContentProvider::queryOutputStream( const rtl::OUString & rUri, 446 const rtl::OUString & rPassword, 447 bool bTruncate ) const 448 throw ( packages::WrongPasswordException ) 449 { 450 if ( m_xStgElemFac.is() ) 451 { 452 try 453 { 454 return 455 m_xStgElemFac->createOutputStream( rUri, rPassword, bTruncate ); 456 } 457 catch ( embed::InvalidStorageException const & ) 458 { 459 OSL_ENSURE( false, "Caught InvalidStorageException!" ); 460 } 461 catch ( lang::IllegalArgumentException const & ) 462 { 463 OSL_ENSURE( false, "Caught IllegalArgumentException!" ); 464 } 465 catch ( io::IOException const & ) 466 { 467 // Okay to happen, for instance when the storage does not exist. 468 //OSL_ENSURE( false, "Caught IOException!" ); 469 } 470 catch ( embed::StorageWrappedTargetException const & ) 471 { 472 OSL_ENSURE( false, "Caught embed::StorageWrappedTargetException!" ); 473 } 474 // catch ( packages::WrongPasswordException const & ) 475 // { 476 // // the key provided is wrong; rethrow; to be handled by caller. 477 // throw; 478 // } 479 } 480 return uno::Reference< io::XOutputStream >(); 481 } 482 483 //========================================================================= 484 uno::Reference< io::XStream > 485 ContentProvider::queryStream( const rtl::OUString & rUri, 486 const rtl::OUString & rPassword, 487 bool bTruncate ) const 488 throw ( packages::WrongPasswordException ) 489 { 490 if ( m_xStgElemFac.is() ) 491 { 492 try 493 { 494 return m_xStgElemFac->createStream( rUri, rPassword, bTruncate ); 495 } 496 catch ( embed::InvalidStorageException const & ) 497 { 498 OSL_ENSURE( false, "Caught InvalidStorageException!" ); 499 } 500 catch ( lang::IllegalArgumentException const & ) 501 { 502 OSL_ENSURE( false, "Caught IllegalArgumentException!" ); 503 } 504 catch ( io::IOException const & ) 505 { 506 // Okay to happen, for instance when the storage does not exist. 507 //OSL_ENSURE( false, "Caught IOException!" ); 508 } 509 catch ( embed::StorageWrappedTargetException const & ) 510 { 511 OSL_ENSURE( false, "Caught embed::StorageWrappedTargetException!" ); 512 } 513 // catch ( packages::WrongPasswordException const & ) 514 // { 515 // // the key provided is wrong; rethrow; to be handled by caller. 516 // throw; 517 // } 518 } 519 return uno::Reference< io::XStream >(); 520 } 521 522 //========================================================================= 523 bool ContentProvider::queryNamesOfChildren( 524 const rtl::OUString & rUri, uno::Sequence< rtl::OUString > & rNames ) const 525 { 526 Uri aUri( rUri ); 527 if ( aUri.isRoot() ) 528 { 529 // special handling for root, which has no storage, but children. 530 if ( m_xDocsMgr.is() ) 531 { 532 rNames = m_xDocsMgr->queryDocuments(); 533 return true; 534 } 535 } 536 else 537 { 538 if ( m_xStgElemFac.is() ) 539 { 540 try 541 { 542 uno::Reference< embed::XStorage > xStorage 543 = m_xStgElemFac->createStorage( rUri, READ ); 544 545 OSL_ENSURE( xStorage.is(), "Got no Storage!" ); 546 547 if ( xStorage.is() ) 548 { 549 uno::Reference< container::XNameAccess > xNA( 550 xStorage, uno::UNO_QUERY ); 551 552 OSL_ENSURE( xNA.is(), "Got no css.container.XNameAccess!" ); 553 if ( xNA.is() ) 554 { 555 rNames = xNA->getElementNames(); 556 return true; 557 } 558 } 559 } 560 catch ( embed::InvalidStorageException const & ) 561 { 562 OSL_ENSURE( false, "Caught InvalidStorageException!" ); 563 } 564 catch ( lang::IllegalArgumentException const & ) 565 { 566 OSL_ENSURE( false, "Caught IllegalArgumentException!" ); 567 } 568 catch ( io::IOException const & ) 569 { 570 // Okay to happen, for instance if the storage does not exist. 571 //OSL_ENSURE( false, "Caught IOException!" ); 572 } 573 catch ( embed::StorageWrappedTargetException const & ) 574 { 575 OSL_ENSURE( false, 576 "Caught embed::StorageWrappedTargetException!" ); 577 } 578 } 579 } 580 return false; 581 } 582 583 //========================================================================= 584 rtl::OUString 585 ContentProvider::queryStorageTitle( const rtl::OUString & rUri ) const 586 { 587 rtl::OUString aTitle; 588 589 Uri aUri( rUri ); 590 if ( aUri.isRoot() ) 591 { 592 // always empty. 593 aTitle = rtl::OUString(); 594 } 595 else if ( aUri.isDocument() ) 596 { 597 // for documents, title shall not be derived from URL. It shall 598 // be somethimg more 'speaking' than just the document UID. 599 if ( m_xDocsMgr.is() ) 600 aTitle = m_xDocsMgr->queryStorageTitle( aUri.getDocumentId() ); 601 } 602 else 603 { 604 // derive title from URL 605 aTitle = aUri.getDecodedName(); 606 } 607 608 OSL_ENSURE( ( aTitle.getLength() > 0 ) || aUri.isRoot(), 609 "ContentProvider::queryStorageTitle - empty title!" ); 610 return aTitle; 611 } 612 613 //========================================================================= 614 uno::Reference< frame::XModel > 615 ContentProvider::queryDocumentModel( const rtl::OUString & rUri ) const 616 { 617 uno::Reference< frame::XModel > xModel; 618 619 if ( m_xDocsMgr.is() ) 620 { 621 Uri aUri( rUri ); 622 xModel = m_xDocsMgr->queryDocumentModel( aUri.getDocumentId() ); 623 } 624 625 OSL_ENSURE( xModel.is(), 626 "ContentProvider::queryDocumentModel - no model!" ); 627 return xModel; 628 } 629 630