1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 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/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 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 . 18 */ 19 20 #include <sal/config.h> 21 22 #include <cassert> 23 24 #include <osl/diagnose.h> 25 #include <osl/mutex.hxx> 26 #include <sal/log.hxx> 27 #include <salhelper/simplereferenceobject.hxx> 28 #include <cppuhelper/weak.hxx> 29 #include <cppuhelper/queryinterface.hxx> 30 31 #include <cppuhelper/implbase.hxx> 32 #include <com/sun/star/ucb/CheckinArgument.hpp> 33 #include <com/sun/star/ucb/ContentCreationError.hpp> 34 #include <com/sun/star/ucb/ContentCreationException.hpp> 35 #include <com/sun/star/ucb/IllegalIdentifierException.hpp> 36 #include <com/sun/star/ucb/XCommandInfo.hpp> 37 #include <com/sun/star/ucb/XCommandProcessor.hpp> 38 #include <com/sun/star/ucb/Command.hpp> 39 #include <com/sun/star/ucb/ContentAction.hpp> 40 #include <com/sun/star/ucb/OpenCommandArgument2.hpp> 41 #include <com/sun/star/ucb/InsertCommandArgument.hpp> 42 #include <com/sun/star/ucb/GlobalTransferCommandArgument2.hpp> 43 #include <com/sun/star/ucb/OpenMode.hpp> 44 #include <com/sun/star/ucb/XContentCreator.hpp> 45 #include <com/sun/star/ucb/XContentEventListener.hpp> 46 #include <com/sun/star/ucb/XDynamicResultSet.hpp> 47 #include <com/sun/star/ucb/SortedDynamicResultSetFactory.hpp> 48 #include <com/sun/star/ucb/UniversalContentBroker.hpp> 49 #include <com/sun/star/ucb/XUniversalContentBroker.hpp> 50 #include <com/sun/star/beans/XPropertySetInfo.hpp> 51 #include <com/sun/star/beans/Property.hpp> 52 #include <com/sun/star/beans/PropertyValue.hpp> 53 #include <com/sun/star/sdbc/XRow.hpp> 54 #include <com/sun/star/lang/IllegalArgumentException.hpp> 55 #include <com/sun/star/beans/UnknownPropertyException.hpp> 56 #include <ucbhelper/content.hxx> 57 #include <ucbhelper/activedatasink.hxx> 58 #include <ucbhelper/activedatastreamer.hxx> 59 #include <ucbhelper/cancelcommandexecution.hxx> 60 61 namespace com::sun::star::ucb { class XCommandEnvironment; } 62 namespace com::sun::star::ucb { class XContentProvider; } 63 namespace com::sun::star::sdbc { class XResultSet; } 64 65 using namespace com::sun::star::container; 66 using namespace com::sun::star::beans; 67 using namespace com::sun::star::io; 68 using namespace com::sun::star::lang; 69 using namespace com::sun::star::sdbc; 70 using namespace com::sun::star::task; 71 using namespace com::sun::star::ucb; 72 using namespace com::sun::star::uno; 73 74 namespace ucbhelper 75 { 76 77 class EmptyInputStream : public ::cppu::WeakImplHelper< XInputStream > 78 { 79 public: 80 virtual sal_Int32 SAL_CALL readBytes( 81 Sequence< sal_Int8 > & data, sal_Int32 nBytesToRead ) override; 82 virtual sal_Int32 SAL_CALL readSomeBytes( 83 Sequence< sal_Int8 > & data, sal_Int32 nMaxBytesToRead ) override; 84 virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override; 85 virtual sal_Int32 SAL_CALL available() override; 86 virtual void SAL_CALL closeInput() override; 87 }; 88 89 sal_Int32 EmptyInputStream::readBytes( 90 Sequence< sal_Int8 > & data, sal_Int32 ) 91 { 92 data.realloc( 0 ); 93 return 0; 94 } 95 96 sal_Int32 EmptyInputStream::readSomeBytes( 97 Sequence< sal_Int8 > & data, sal_Int32 ) 98 { 99 data.realloc( 0 ); 100 return 0; 101 } 102 103 void EmptyInputStream::skipBytes( sal_Int32 ) 104 { 105 } 106 107 sal_Int32 EmptyInputStream::available() 108 { 109 return 0; 110 } 111 112 void EmptyInputStream::closeInput() 113 { 114 } 115 116 117 // class ContentEventListener_Impl. 118 119 120 class ContentEventListener_Impl : public cppu::OWeakObject, 121 public XContentEventListener 122 { 123 Content_Impl& m_rContent; 124 125 public: 126 explicit ContentEventListener_Impl( Content_Impl& rContent ) 127 : m_rContent( rContent ) {} 128 129 // XInterface 130 virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; 131 virtual void SAL_CALL acquire() 132 throw() override; 133 virtual void SAL_CALL release() 134 throw() override; 135 136 // XContentEventListener 137 virtual void SAL_CALL contentEvent( const ContentEvent& evt ) override; 138 139 // XEventListener ( base of XContentEventListener ) 140 virtual void SAL_CALL disposing( const EventObject& Source ) override; 141 }; 142 143 144 // class Content_Impl. 145 146 147 class Content_Impl : public salhelper::SimpleReferenceObject 148 { 149 friend class ContentEventListener_Impl; 150 151 mutable OUString m_aURL; 152 Reference< XComponentContext > m_xCtx; 153 Reference< XContent > m_xContent; 154 Reference< XCommandProcessor > m_xCommandProcessor; 155 Reference< XCommandEnvironment > m_xEnv; 156 Reference< XContentEventListener > m_xContentEventListener; 157 mutable osl::Mutex m_aMutex; 158 159 private: 160 void reinit( const Reference< XContent >& xContent ); 161 void disposing(const EventObject& Source); 162 163 public: 164 Content_Impl() {}; 165 Content_Impl( const Reference< XComponentContext >& rCtx, 166 const Reference< XContent >& rContent, 167 const Reference< XCommandEnvironment >& rEnv ); 168 169 virtual ~Content_Impl() override; 170 171 const OUString& getURL() const; 172 Reference< XContent > getContent(); 173 Reference< XCommandProcessor > getCommandProcessor(); 174 Reference< XComponentContext > const & getComponentContext() const 175 { assert(m_xCtx.is()); return m_xCtx; } 176 177 Any executeCommand( const Command& rCommand ); 178 179 inline const Reference< XCommandEnvironment >& getEnvironment() const; 180 inline void setEnvironment( 181 const Reference< XCommandEnvironment >& xNewEnv ); 182 183 void inserted(); 184 }; 185 186 187 // Helpers. 188 189 /// @throws ContentCreationException 190 /// @throws RuntimeException 191 static void ensureContentProviderForURL( const Reference< XUniversalContentBroker >& rBroker, 192 const OUString & rURL ) 193 { 194 Reference< XContentProvider > xProv 195 = rBroker->queryContentProvider( rURL ); 196 if ( !xProv.is() ) 197 { 198 throw ContentCreationException( 199 "No Content Provider available for URL: " + rURL, 200 Reference< XInterface >(), 201 ContentCreationError_NO_CONTENT_PROVIDER ); 202 } 203 } 204 205 /// @throws ContentCreationException 206 /// @throws RuntimeException 207 static Reference< XContentIdentifier > getContentIdentifierThrow( 208 const Reference< XUniversalContentBroker > & rBroker, 209 const OUString & rURL) 210 { 211 Reference< XContentIdentifier > xId 212 = rBroker->createContentIdentifier( rURL ); 213 214 if (!xId.is()) 215 { 216 ensureContentProviderForURL( rBroker, rURL ); 217 218 throw ContentCreationException( 219 "Unable to create Content Identifier!", 220 Reference< XInterface >(), 221 ContentCreationError_IDENTIFIER_CREATION_FAILED ); 222 } 223 224 return xId; 225 } 226 227 /// @throws RuntimeException 228 static Reference< XContentIdentifier > getContentIdentifierNoThrow( 229 const Reference< XUniversalContentBroker > & rBroker, 230 const OUString & rURL) 231 { 232 return rBroker->createContentIdentifier(rURL); 233 } 234 235 /// @throws ContentCreationException 236 /// @throws RuntimeException 237 static Reference< XContent > getContentThrow( 238 const Reference< XUniversalContentBroker > & rBroker, 239 const Reference< XContentIdentifier > & xId) 240 { 241 Reference< XContent > xContent; 242 OUString msg; 243 try 244 { 245 xContent = rBroker->queryContent( xId ); 246 } 247 catch ( IllegalIdentifierException const & e ) 248 { 249 msg = e.Message; 250 // handled below. 251 } 252 253 if ( !xContent.is() ) 254 { 255 ensureContentProviderForURL( rBroker, xId->getContentIdentifier() ); 256 257 throw ContentCreationException( 258 "Unable to create Content for <" + xId->getContentIdentifier() + ">: " + msg, 259 Reference< XInterface >(), 260 ContentCreationError_CONTENT_CREATION_FAILED ); 261 } 262 263 return xContent; 264 } 265 266 /// @throws RuntimeException 267 static Reference< XContent > getContentNoThrow( 268 const Reference< XUniversalContentBroker > & rBroker, 269 const Reference< XContentIdentifier > & xId) 270 { 271 Reference< XContent > xContent; 272 try 273 { 274 xContent = rBroker->queryContent( xId ); 275 } 276 catch ( IllegalIdentifierException const & e ) 277 { 278 SAL_WARN("ucbhelper", "getContentNoThrow: " << e); 279 } 280 281 return xContent; 282 } 283 284 285 // Content Implementation. 286 287 288 Content::Content() 289 : m_xImpl( new Content_Impl ) 290 { 291 } 292 293 294 Content::Content( const OUString& rURL, 295 const Reference< XCommandEnvironment >& rEnv, 296 const Reference< XComponentContext >& rCtx ) 297 { 298 Reference< XUniversalContentBroker > pBroker( 299 UniversalContentBroker::create( rCtx ) ); 300 301 Reference< XContentIdentifier > xId 302 = getContentIdentifierThrow(pBroker, rURL); 303 304 Reference< XContent > xContent = getContentThrow(pBroker, xId); 305 306 m_xImpl = new Content_Impl( rCtx, xContent, rEnv ); 307 } 308 309 310 Content::Content( const Reference< XContent >& rContent, 311 const Reference< XCommandEnvironment >& rEnv, 312 const Reference< XComponentContext >& rCtx ) 313 { 314 m_xImpl = new Content_Impl( rCtx, rContent, rEnv ); 315 } 316 317 318 Content::Content( const Content& rOther ) 319 { 320 m_xImpl = rOther.m_xImpl; 321 } 322 323 Content::Content( Content&& rOther ) noexcept 324 { 325 m_xImpl = std::move(rOther.m_xImpl); 326 } 327 328 // static 329 bool Content::create( const OUString& rURL, 330 const Reference< XCommandEnvironment >& rEnv, 331 const Reference< XComponentContext >& rCtx, 332 Content& rContent ) 333 { 334 Reference< XUniversalContentBroker > pBroker( 335 UniversalContentBroker::create( rCtx ) ); 336 337 Reference< XContentIdentifier > xId 338 = getContentIdentifierNoThrow(pBroker, rURL); 339 if ( !xId.is() ) 340 return false; 341 342 Reference< XContent > xContent = getContentNoThrow(pBroker, xId); 343 if ( !xContent.is() ) 344 return false; 345 346 rContent.m_xImpl 347 = new Content_Impl( rCtx, xContent, rEnv ); 348 349 return true; 350 } 351 352 353 Content::~Content() 354 { 355 } 356 357 358 Content& Content::operator=( const Content& rOther ) 359 { 360 m_xImpl = rOther.m_xImpl; 361 return *this; 362 } 363 364 Content& Content::operator=( Content&& rOther ) noexcept 365 { 366 m_xImpl = std::move(rOther.m_xImpl); 367 return *this; 368 } 369 370 Reference< XContent > Content::get() const 371 { 372 return m_xImpl->getContent(); 373 } 374 375 376 const OUString& Content::getURL() const 377 { 378 return m_xImpl->getURL(); 379 } 380 381 382 const Reference< XCommandEnvironment >& Content::getCommandEnvironment() const 383 { 384 return m_xImpl->getEnvironment(); 385 } 386 387 388 void Content::setCommandEnvironment( 389 const Reference< XCommandEnvironment >& xNewEnv ) 390 { 391 m_xImpl->setEnvironment( xNewEnv ); 392 } 393 394 395 Reference< XCommandInfo > Content::getCommands() 396 { 397 Command aCommand; 398 aCommand.Name = "getCommandInfo"; 399 aCommand.Handle = -1; // n/a 400 aCommand.Argument = Any(); 401 402 Any aResult = m_xImpl->executeCommand( aCommand ); 403 404 Reference< XCommandInfo > xInfo; 405 aResult >>= xInfo; 406 return xInfo; 407 } 408 409 410 Reference< XPropertySetInfo > Content::getProperties() 411 { 412 Command aCommand; 413 aCommand.Name = "getPropertySetInfo"; 414 aCommand.Handle = -1; // n/a 415 aCommand.Argument = Any(); 416 417 Any aResult = m_xImpl->executeCommand( aCommand ); 418 419 Reference< XPropertySetInfo > xInfo; 420 aResult >>= xInfo; 421 return xInfo; 422 } 423 424 425 Any Content::getPropertyValue( const OUString& rPropertyName ) 426 { 427 Sequence<OUString> aNames { rPropertyName }; 428 429 Sequence< Any > aRet = getPropertyValues( aNames ); 430 return aRet.getConstArray()[ 0 ]; 431 } 432 433 434 Any Content::setPropertyValue( const OUString& rName, 435 const Any& rValue ) 436 { 437 Sequence<OUString> aNames { rName }; 438 439 Sequence< Any > aValues( 1 ); 440 aValues.getArray()[ 0 ] = rValue; 441 442 Sequence< Any > aErrors = setPropertyValues( aNames, aValues ); 443 return aErrors.getConstArray()[ 0 ]; 444 } 445 446 447 Sequence< Any > Content::getPropertyValues( 448 const Sequence< OUString >& rPropertyNames ) 449 { 450 Reference< XRow > xRow = getPropertyValuesInterface( rPropertyNames ); 451 452 sal_Int32 nCount = rPropertyNames.getLength(); 453 Sequence< Any > aValues( nCount ); 454 455 if ( xRow.is() ) 456 { 457 Any* pValues = aValues.getArray(); 458 459 for ( sal_Int32 n = 0; n < nCount; ++n ) 460 pValues[ n ] = xRow->getObject( n + 1, Reference< XNameAccess >() ); 461 } 462 463 return aValues; 464 } 465 466 467 Reference< XRow > Content::getPropertyValuesInterface( 468 const Sequence< OUString >& rPropertyNames ) 469 { 470 sal_Int32 nCount = rPropertyNames.getLength(); 471 Sequence< Property > aProps( nCount ); 472 Property* pProps = aProps.getArray(); 473 474 const OUString* pNames = rPropertyNames.getConstArray(); 475 476 for ( sal_Int32 n = 0; n< nCount; ++n ) 477 { 478 Property& rProp = pProps[ n ]; 479 480 rProp.Name = pNames[ n ]; 481 rProp.Handle = -1; // n/a 482 // rProp.Type = 483 // rProp.Attributes = ; 484 } 485 486 Command aCommand; 487 aCommand.Name = "getPropertyValues"; 488 aCommand.Handle = -1; // n/a 489 aCommand.Argument <<= aProps; 490 491 Any aResult = m_xImpl->executeCommand( aCommand ); 492 493 Reference< XRow > xRow; 494 aResult >>= xRow; 495 return xRow; 496 } 497 498 499 Sequence< Any > Content::setPropertyValues( 500 const Sequence< OUString >& rPropertyNames, 501 const Sequence< Any >& rValues ) 502 { 503 if ( rPropertyNames.getLength() != rValues.getLength() ) 504 { 505 ucbhelper::cancelCommandExecution( 506 makeAny( IllegalArgumentException( 507 "Length of property names sequence and value " 508 "sequence are unequal!", 509 get(), 510 -1 ) ), 511 m_xImpl->getEnvironment() ); 512 // Unreachable 513 } 514 515 sal_Int32 nCount = rValues.getLength(); 516 Sequence< PropertyValue > aProps( nCount ); 517 PropertyValue* pProps = aProps.getArray(); 518 519 const OUString* pNames = rPropertyNames.getConstArray(); 520 const Any* pValues = rValues.getConstArray(); 521 522 for ( sal_Int32 n = 0; n< nCount; ++n ) 523 { 524 PropertyValue& rProp = pProps[ n ]; 525 526 rProp.Name = pNames[ n ]; 527 rProp.Handle = -1; // n/a 528 rProp.Value = pValues[ n ]; 529 // rProp.State = ; 530 } 531 532 Command aCommand; 533 aCommand.Name = "setPropertyValues"; 534 aCommand.Handle = -1; // n/a 535 aCommand.Argument <<= aProps; 536 537 Any aResult = m_xImpl->executeCommand( aCommand ); 538 539 Sequence< Any > aErrors; 540 aResult >>= aErrors; 541 return aErrors; 542 } 543 544 545 Any Content::executeCommand( const OUString& rCommandName, 546 const Any& rCommandArgument ) 547 { 548 Command aCommand; 549 aCommand.Name = rCommandName; 550 aCommand.Handle = -1; // n/a 551 aCommand.Argument = rCommandArgument; 552 553 return m_xImpl->executeCommand( aCommand ); 554 } 555 556 557 Any Content::createCursorAny( const Sequence< OUString >& rPropertyNames, 558 ResultSetInclude eMode ) 559 { 560 sal_Int32 nCount = rPropertyNames.getLength(); 561 Sequence< Property > aProps( nCount ); 562 Property* pProps = aProps.getArray(); 563 const OUString* pNames = rPropertyNames.getConstArray(); 564 for ( sal_Int32 n = 0; n < nCount; ++n ) 565 { 566 Property& rProp = pProps[ n ]; 567 rProp.Name = pNames[ n ]; 568 rProp.Handle = -1; // n/a 569 } 570 571 OpenCommandArgument2 aArg; 572 aArg.Mode = ( eMode == INCLUDE_FOLDERS_ONLY ) 573 ? OpenMode::FOLDERS 574 : ( eMode == INCLUDE_DOCUMENTS_ONLY ) 575 ? OpenMode::DOCUMENTS : OpenMode::ALL; 576 aArg.Priority = 0; // unused 577 aArg.Sink.clear(); // unused 578 aArg.Properties = aProps; 579 580 Command aCommand; 581 aCommand.Name = "open"; 582 aCommand.Handle = -1; // n/a 583 aCommand.Argument <<= aArg; 584 585 return m_xImpl->executeCommand( aCommand ); 586 } 587 588 589 Reference< XResultSet > Content::createCursor( 590 const Sequence< OUString >& rPropertyNames, 591 ResultSetInclude eMode ) 592 { 593 Any aCursorAny = createCursorAny( rPropertyNames, eMode ); 594 595 Reference< XDynamicResultSet > xDynSet; 596 Reference< XResultSet > aResult; 597 598 aCursorAny >>= xDynSet; 599 if ( xDynSet.is() ) 600 aResult = xDynSet->getStaticResultSet(); 601 602 OSL_ENSURE( aResult.is(), "Content::createCursor - no cursor!" ); 603 604 if ( !aResult.is() ) 605 { 606 // Former, the open command directly returned a XResultSet. 607 aCursorAny >>= aResult; 608 609 OSL_ENSURE( !aResult.is(), 610 "Content::createCursor - open-Command must " 611 "return a Reference< XDynnamicResultSet >!" ); 612 } 613 614 return aResult; 615 } 616 617 618 Reference< XDynamicResultSet > Content::createDynamicCursor( 619 const Sequence< OUString >& rPropertyNames, 620 ResultSetInclude eMode ) 621 { 622 Reference< XDynamicResultSet > aResult; 623 createCursorAny( rPropertyNames, eMode ) >>= aResult; 624 625 OSL_ENSURE( aResult.is(), "Content::createDynamicCursor - no cursor!" ); 626 627 return aResult; 628 } 629 630 631 Reference< XResultSet > Content::createSortedCursor( 632 const Sequence< OUString >& rPropertyNames, 633 const Sequence< NumberedSortingInfo >& rSortInfo, 634 const Reference< XAnyCompareFactory >& rAnyCompareFactory, 635 ResultSetInclude eMode ) 636 { 637 Reference< XResultSet > aResult; 638 Reference< XDynamicResultSet > aDynSet; 639 640 Any aCursorAny = createCursorAny( rPropertyNames, eMode ); 641 642 aCursorAny >>= aDynSet; 643 644 if( aDynSet.is() ) 645 { 646 Reference< XDynamicResultSet > aDynResult; 647 648 if( m_xImpl->getComponentContext().is() ) 649 { 650 Reference< XSortedDynamicResultSetFactory > aSortFactory = 651 SortedDynamicResultSetFactory::create( m_xImpl->getComponentContext()); 652 653 aDynResult = aSortFactory->createSortedDynamicResultSet( aDynSet, 654 rSortInfo, 655 rAnyCompareFactory ); 656 } 657 658 OSL_ENSURE( aDynResult.is(), "Content::createSortedCursor - no sorted cursor!" ); 659 660 if( aDynResult.is() ) 661 aResult = aDynResult->getStaticResultSet(); 662 else 663 aResult = aDynSet->getStaticResultSet(); 664 } 665 666 OSL_ENSURE( aResult.is(), "Content::createSortedCursor - no cursor!" ); 667 668 if ( !aResult.is() ) 669 { 670 // Former, the open command directly returned a XResultSet. 671 aCursorAny >>= aResult; 672 673 OSL_ENSURE( !aResult.is(), 674 "Content::createCursor - open-Command must " 675 "return a Reference< XDynnamicResultSet >!" ); 676 } 677 678 return aResult; 679 } 680 681 682 Reference< XInputStream > Content::openStream() 683 { 684 if ( !isDocument() ) 685 return Reference< XInputStream >(); 686 687 Reference< XActiveDataSink > xSink = new ActiveDataSink; 688 689 OpenCommandArgument2 aArg; 690 aArg.Mode = OpenMode::DOCUMENT; 691 aArg.Priority = 0; // unused 692 aArg.Sink = xSink; 693 aArg.Properties = Sequence< Property >( 0 ); // unused 694 695 Command aCommand; 696 aCommand.Name = "open"; 697 aCommand.Handle = -1; // n/a 698 aCommand.Argument <<= aArg; 699 700 m_xImpl->executeCommand( aCommand ); 701 702 return xSink->getInputStream(); 703 } 704 705 706 Reference< XInputStream > Content::openStreamNoLock() 707 { 708 if ( !isDocument() ) 709 return Reference< XInputStream >(); 710 711 Reference< XActiveDataSink > xSink = new ActiveDataSink; 712 713 OpenCommandArgument2 aArg; 714 aArg.Mode = OpenMode::DOCUMENT_SHARE_DENY_NONE; 715 aArg.Priority = 0; // unused 716 aArg.Sink = xSink; 717 aArg.Properties = Sequence< Property >( 0 ); // unused 718 719 Command aCommand; 720 aCommand.Name = "open"; 721 aCommand.Handle = -1; // n/a 722 aCommand.Argument <<= aArg; 723 724 m_xImpl->executeCommand( aCommand ); 725 726 return xSink->getInputStream(); 727 } 728 729 730 Reference< XStream > Content::openWriteableStream() 731 { 732 if ( !isDocument() ) 733 return Reference< XStream >(); 734 735 Reference< XActiveDataStreamer > xStreamer = new ActiveDataStreamer; 736 737 OpenCommandArgument2 aArg; 738 aArg.Mode = OpenMode::DOCUMENT; 739 aArg.Priority = 0; // unused 740 aArg.Sink = xStreamer; 741 aArg.Properties = Sequence< Property >( 0 ); // unused 742 743 Command aCommand; 744 aCommand.Name = "open"; 745 aCommand.Handle = -1; // n/a 746 aCommand.Argument <<= aArg; 747 748 m_xImpl->executeCommand( aCommand ); 749 750 return xStreamer->getStream(); 751 } 752 753 754 Reference< XStream > Content::openWriteableStreamNoLock() 755 { 756 if ( !isDocument() ) 757 return Reference< XStream >(); 758 759 Reference< XActiveDataStreamer > xStreamer = new ActiveDataStreamer; 760 761 OpenCommandArgument2 aArg; 762 aArg.Mode = OpenMode::DOCUMENT_SHARE_DENY_NONE; 763 aArg.Priority = 0; // unused 764 aArg.Sink = xStreamer; 765 aArg.Properties = Sequence< Property >( 0 ); // unused 766 767 Command aCommand; 768 aCommand.Name = "open"; 769 aCommand.Handle = -1; // n/a 770 aCommand.Argument <<= aArg; 771 772 m_xImpl->executeCommand( aCommand ); 773 774 return xStreamer->getStream(); 775 } 776 777 778 bool Content::openStream( const Reference< XActiveDataSink >& rSink ) 779 { 780 if ( !isDocument() ) 781 return false; 782 783 OpenCommandArgument2 aArg; 784 aArg.Mode = OpenMode::DOCUMENT; 785 aArg.Priority = 0; // unused 786 aArg.Sink = rSink; 787 aArg.Properties = Sequence< Property >( 0 ); // unused 788 789 Command aCommand; 790 aCommand.Name = "open"; 791 aCommand.Handle = -1; // n/a 792 aCommand.Argument <<= aArg; 793 794 m_xImpl->executeCommand( aCommand ); 795 796 return true; 797 } 798 799 800 bool Content::openStream( const Reference< XOutputStream >& rStream ) 801 { 802 if ( !isDocument() ) 803 return false; 804 805 OpenCommandArgument2 aArg; 806 aArg.Mode = OpenMode::DOCUMENT; 807 aArg.Priority = 0; // unused 808 aArg.Sink = rStream; 809 aArg.Properties = Sequence< Property >( 0 ); // unused 810 811 Command aCommand; 812 aCommand.Name = "open"; 813 aCommand.Handle = -1; // n/a 814 aCommand.Argument <<= aArg; 815 816 m_xImpl->executeCommand( aCommand ); 817 818 return true; 819 } 820 821 822 void Content::writeStream( const Reference< XInputStream >& rStream, 823 bool bReplaceExisting ) 824 { 825 InsertCommandArgument aArg; 826 aArg.Data = rStream.is() ? rStream : new EmptyInputStream; 827 aArg.ReplaceExisting = bReplaceExisting; 828 829 Command aCommand; 830 aCommand.Name = "insert"; 831 aCommand.Handle = -1; // n/a 832 aCommand.Argument <<= aArg; 833 834 m_xImpl->executeCommand( aCommand ); 835 836 m_xImpl->inserted(); 837 } 838 839 840 Sequence< ContentInfo > Content::queryCreatableContentsInfo() 841 { 842 // First, try it using "CreatableContentsInfo" property -> the "new" way. 843 Sequence< ContentInfo > aInfo; 844 if ( getPropertyValue( 845 "CreatableContentsInfo" ) 846 >>= aInfo ) 847 return aInfo; 848 849 // Second, try it using XContentCreator interface -> the "old" way (not 850 // providing the chance to supply an XCommandEnvironment. 851 Reference< XContentCreator > xCreator( m_xImpl->getContent(), UNO_QUERY ); 852 if ( xCreator.is() ) 853 aInfo = xCreator->queryCreatableContentsInfo(); 854 855 return aInfo; 856 } 857 858 859 bool Content::insertNewContent( const OUString& rContentType, 860 const Sequence< OUString >& 861 rPropertyNames, 862 const Sequence< Any >& rPropertyValues, 863 Content& rNewContent ) 864 { 865 return insertNewContent( rContentType, 866 rPropertyNames, 867 rPropertyValues, 868 new EmptyInputStream, 869 rNewContent ); 870 } 871 872 873 bool Content::insertNewContent( const OUString& rContentType, 874 const Sequence< OUString >& 875 rPropertyNames, 876 const Sequence< Any >& rPropertyValues, 877 const Reference< XInputStream >& rData, 878 Content& rNewContent ) 879 { 880 if ( rContentType.isEmpty() ) 881 return false; 882 883 // First, try it using "createNewContent" command -> the "new" way. 884 ContentInfo aInfo; 885 aInfo.Type = rContentType; 886 aInfo.Attributes = 0; 887 888 Command aCommand; 889 aCommand.Name = "createNewContent"; 890 aCommand.Handle = -1; // n/a 891 aCommand.Argument <<= aInfo; 892 893 Reference< XContent > xNew; 894 try 895 { 896 m_xImpl->executeCommand( aCommand ) >>= xNew; 897 } 898 catch ( RuntimeException const & ) 899 { 900 throw; 901 } 902 catch ( Exception const & ) 903 { 904 } 905 906 if ( !xNew.is() ) 907 { 908 // Second, try it using XContentCreator interface -> the "old" 909 // way (not providing the chance to supply an XCommandEnvironment. 910 Reference< XContentCreator > xCreator( m_xImpl->getContent(), UNO_QUERY ); 911 912 if ( !xCreator.is() ) 913 return false; 914 915 xNew = xCreator->createNewContent( aInfo ); 916 917 if ( !xNew.is() ) 918 return false; 919 } 920 921 Content aNewContent( 922 xNew, m_xImpl->getEnvironment(), m_xImpl->getComponentContext() ); 923 aNewContent.setPropertyValues( rPropertyNames, rPropertyValues ); 924 aNewContent.executeCommand( "insert", 925 makeAny( 926 InsertCommandArgument( 927 rData.is() ? rData : new EmptyInputStream, 928 false /* ReplaceExisting */ ) ) ); 929 aNewContent.m_xImpl->inserted(); 930 931 rNewContent = aNewContent; 932 return true; 933 } 934 935 936 void Content::transferContent( const Content& rSourceContent, 937 InsertOperation eOperation, 938 const OUString & rTitle, 939 const sal_Int32 nNameClashAction, 940 const OUString & rMimeType, 941 bool bMajorVersion, 942 const OUString & rVersionComment, 943 OUString* pResultURL, 944 const OUString & rDocumentId ) const 945 { 946 Reference< XUniversalContentBroker > pBroker( 947 UniversalContentBroker::create( m_xImpl->getComponentContext() ) ); 948 949 // Execute command "globalTransfer" at UCB. 950 951 TransferCommandOperation eTransOp = TransferCommandOperation(); 952 OUString sCommand( "globalTransfer" ); 953 bool bCheckIn = false; 954 switch ( eOperation ) 955 { 956 case InsertOperation::Copy: 957 eTransOp = TransferCommandOperation_COPY; 958 break; 959 960 case InsertOperation::Move: 961 eTransOp = TransferCommandOperation_MOVE; 962 break; 963 964 case InsertOperation::Checkin: 965 eTransOp = TransferCommandOperation_COPY; 966 sCommand = "checkin"; 967 bCheckIn = true; 968 break; 969 } 970 Command aCommand; 971 aCommand.Name = sCommand; 972 aCommand.Handle = -1; // n/a 973 974 if ( !bCheckIn ) 975 { 976 GlobalTransferCommandArgument2 aTransferArg( 977 eTransOp, 978 rSourceContent.getURL(), // SourceURL 979 getURL(), // TargetFolderURL, 980 rTitle, 981 nNameClashAction, 982 rMimeType, 983 rDocumentId ); 984 aCommand.Argument <<= aTransferArg; 985 } 986 else 987 { 988 CheckinArgument aCheckinArg( bMajorVersion, rVersionComment, 989 rSourceContent.getURL(), getURL(), rTitle, rMimeType ); 990 aCommand.Argument <<= aCheckinArg; 991 } 992 993 Any aRet = pBroker->execute( aCommand, 0, m_xImpl->getEnvironment() ); 994 if ( pResultURL != nullptr ) 995 aRet >>= *pResultURL; 996 } 997 998 999 bool Content::isFolder() 1000 { 1001 bool bFolder = false; 1002 if ( getPropertyValue("IsFolder") 1003 >>= bFolder ) 1004 return bFolder; 1005 1006 ucbhelper::cancelCommandExecution( 1007 makeAny( UnknownPropertyException( 1008 "Unable to retrieve value of property 'IsFolder'!", 1009 get() ) ), 1010 m_xImpl->getEnvironment() ); 1011 1012 #if !(defined(_MSC_VER) && defined(ENABLE_LTO)) 1013 // Unreachable - cancelCommandExecution always throws an exception. 1014 // But some compilers complain... 1015 return false; 1016 #endif 1017 } 1018 1019 1020 SAL_WNOUNREACHABLE_CODE_PUSH 1021 1022 bool Content::isDocument() 1023 { 1024 bool bDoc = false; 1025 if ( getPropertyValue("IsDocument") 1026 >>= bDoc ) 1027 return bDoc; 1028 1029 ucbhelper::cancelCommandExecution( 1030 makeAny( UnknownPropertyException( 1031 "Unable to retrieve value of property 'IsDocument'!", 1032 get() ) ), 1033 m_xImpl->getEnvironment() ); 1034 1035 // Unreachable - cancelCommandExecution always throws an exception, 1036 // But some compilers complain... 1037 return false; 1038 } 1039 1040 SAL_WNOUNREACHABLE_CODE_POP 1041 1042 void Content::lock() 1043 { 1044 Command aCommand; 1045 aCommand.Name = "lock"; 1046 aCommand.Handle = -1; // n/a 1047 1048 m_xImpl->executeCommand( aCommand ); 1049 1050 } 1051 1052 void Content::unlock() 1053 { 1054 1055 Command aCommand; 1056 aCommand.Name = "unlock"; 1057 aCommand.Handle = -1; // n/a 1058 1059 m_xImpl->executeCommand( aCommand ); 1060 1061 } 1062 1063 1064 // Content_Impl Implementation. 1065 1066 1067 Content_Impl::Content_Impl( const Reference< XComponentContext >& rCtx, 1068 const Reference< XContent >& rContent, 1069 const Reference< XCommandEnvironment >& rEnv ) 1070 : m_xCtx( rCtx ), 1071 m_xContent( rContent ), 1072 m_xEnv( rEnv ) 1073 { 1074 assert(rCtx.is()); 1075 if ( m_xContent.is() ) 1076 { 1077 m_xContentEventListener = new ContentEventListener_Impl( *this ); 1078 m_xContent->addContentEventListener( m_xContentEventListener ); 1079 1080 #if OSL_DEBUG_LEVEL > 0 1081 // Only done on demand in product version for performance reasons, 1082 // but a nice debug helper. 1083 getURL(); 1084 #endif 1085 } 1086 } 1087 1088 1089 void Content_Impl::reinit( const Reference< XContent >& xContent ) 1090 { 1091 osl::MutexGuard aGuard( m_aMutex ); 1092 1093 m_xCommandProcessor = nullptr; 1094 1095 // #92581# - Don't reset m_aURL!!! 1096 1097 if ( m_xContent.is() ) 1098 { 1099 try 1100 { 1101 m_xContent->removeContentEventListener( m_xContentEventListener ); 1102 } 1103 catch ( RuntimeException const & ) 1104 { 1105 } 1106 } 1107 1108 if ( xContent.is() ) 1109 { 1110 m_xContent = xContent; 1111 m_xContent->addContentEventListener( m_xContentEventListener ); 1112 1113 #if OSL_DEBUG_LEVEL > 0 1114 // Only done on demand in product version for performance reasons, 1115 // but a nice debug helper. 1116 getURL(); 1117 #endif 1118 } 1119 else 1120 { 1121 // We need m_xContent's URL in order to be able to create the 1122 // content object again if demanded ( --> Content_Impl::getContent() ) 1123 getURL(); 1124 1125 m_xContent = nullptr; 1126 } 1127 } 1128 1129 1130 // virtual 1131 Content_Impl::~Content_Impl() 1132 { 1133 if ( m_xContent.is() ) 1134 { 1135 try 1136 { 1137 m_xContent->removeContentEventListener( m_xContentEventListener ); 1138 } 1139 catch ( RuntimeException const & ) 1140 { 1141 } 1142 } 1143 } 1144 1145 1146 void Content_Impl::disposing( const EventObject& Source ) 1147 { 1148 Reference<XContent> xContent; 1149 1150 { 1151 osl::MutexGuard aGuard( m_aMutex ); 1152 if(Source.Source != m_xContent) 1153 return; 1154 1155 xContent = m_xContent; 1156 1157 m_aURL.clear(); 1158 m_xCommandProcessor = nullptr; 1159 m_xContent = nullptr; 1160 } 1161 1162 if ( xContent.is() ) 1163 { 1164 try 1165 { 1166 xContent->removeContentEventListener( m_xContentEventListener ); 1167 } 1168 catch ( RuntimeException const & ) 1169 { 1170 } 1171 } 1172 } 1173 1174 1175 const OUString& Content_Impl::getURL() const 1176 { 1177 if ( m_aURL.isEmpty() && m_xContent.is() ) 1178 { 1179 osl::MutexGuard aGuard( m_aMutex ); 1180 1181 if ( m_aURL.isEmpty() && m_xContent.is() ) 1182 { 1183 Reference< XContentIdentifier > xId = m_xContent->getIdentifier(); 1184 if ( xId.is() ) 1185 m_aURL = xId->getContentIdentifier(); 1186 } 1187 } 1188 1189 return m_aURL; 1190 } 1191 1192 1193 Reference< XContent > Content_Impl::getContent() 1194 { 1195 if ( !m_xContent.is() && !m_aURL.isEmpty() ) 1196 { 1197 osl::MutexGuard aGuard( m_aMutex ); 1198 1199 if ( !m_xContent.is() && !m_aURL.isEmpty() ) 1200 { 1201 Reference< XUniversalContentBroker > pBroker( 1202 UniversalContentBroker::create( getComponentContext() ) ); 1203 1204 OSL_ENSURE( pBroker->queryContentProviders().hasElements(), 1205 "Content Broker not configured (no providers)!" ); 1206 1207 Reference< XContentIdentifier > xId 1208 = pBroker->createContentIdentifier( m_aURL ); 1209 1210 OSL_ENSURE( xId.is(), "No Content Identifier!" ); 1211 1212 if ( xId.is() ) 1213 { 1214 try 1215 { 1216 m_xContent = pBroker->queryContent( xId ); 1217 } 1218 catch ( IllegalIdentifierException const & ) 1219 { 1220 } 1221 1222 if ( m_xContent.is() ) 1223 m_xContent->addContentEventListener( 1224 m_xContentEventListener ); 1225 } 1226 } 1227 } 1228 1229 return m_xContent; 1230 } 1231 1232 1233 Reference< XCommandProcessor > Content_Impl::getCommandProcessor() 1234 { 1235 if ( !m_xCommandProcessor.is() ) 1236 { 1237 osl::MutexGuard aGuard( m_aMutex ); 1238 1239 if ( !m_xCommandProcessor.is() ) 1240 m_xCommandProcessor.set( getContent(), UNO_QUERY ); 1241 } 1242 1243 return m_xCommandProcessor; 1244 } 1245 1246 1247 Any Content_Impl::executeCommand( const Command& rCommand ) 1248 { 1249 Reference< XCommandProcessor > xProc = getCommandProcessor(); 1250 if ( !xProc.is() ) 1251 return Any(); 1252 1253 // Execute command 1254 return xProc->execute( rCommand, 0, m_xEnv ); 1255 } 1256 1257 1258 inline const Reference< XCommandEnvironment >& 1259 Content_Impl::getEnvironment() const 1260 { 1261 return m_xEnv; 1262 } 1263 1264 1265 inline void Content_Impl::setEnvironment( 1266 const Reference< XCommandEnvironment >& xNewEnv ) 1267 { 1268 osl::MutexGuard aGuard( m_aMutex ); 1269 m_xEnv = xNewEnv; 1270 } 1271 1272 1273 void Content_Impl::inserted() 1274 { 1275 // URL might have changed during 'insert' => recalculate in next getURL() 1276 osl::MutexGuard aGuard( m_aMutex ); 1277 m_aURL.clear(); 1278 } 1279 1280 1281 // ContentEventListener_Impl Implementation. 1282 1283 1284 // XInterface methods. 1285 1286 void SAL_CALL ContentEventListener_Impl::acquire() 1287 throw() 1288 { 1289 OWeakObject::acquire(); 1290 } 1291 1292 void SAL_CALL ContentEventListener_Impl::release() 1293 throw() 1294 { 1295 OWeakObject::release(); 1296 } 1297 1298 css::uno::Any SAL_CALL ContentEventListener_Impl::queryInterface( const css::uno::Type & rType ) 1299 { 1300 css::uno::Any aRet = cppu::queryInterface( rType, 1301 static_cast< XContentEventListener* >(this), 1302 static_cast< XEventListener* >(this) 1303 ); 1304 return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); 1305 } 1306 1307 // XContentEventListener methods. 1308 1309 1310 // virtual 1311 void SAL_CALL ContentEventListener_Impl::contentEvent( const ContentEvent& evt ) 1312 { 1313 if ( evt.Source == m_rContent.m_xContent ) 1314 { 1315 switch ( evt.Action ) 1316 { 1317 case ContentAction::DELETED: 1318 m_rContent.reinit( Reference< XContent >() ); 1319 break; 1320 1321 case ContentAction::EXCHANGED: 1322 m_rContent.reinit( evt.Content ); 1323 break; 1324 1325 default: 1326 break; 1327 } 1328 } 1329 } 1330 1331 1332 // XEventListenr methods. 1333 1334 1335 // virtual 1336 void SAL_CALL ContentEventListener_Impl::disposing( const EventObject& Source ) 1337 { 1338 m_rContent.disposing(Source); 1339 } 1340 1341 } /* namespace ucbhelper */ 1342 1343 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 1344
