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