/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_ucb.hxx" /************************************************************************** TODO ************************************************************************** *************************************************************************/ #include "osl/diagnose.h" #include "osl/doublecheckedlocking.h" #include "rtl/ustrbuf.hxx" #include "com/sun/star/beans/PropertyAttribute.hpp" #include "com/sun/star/beans/PropertyValue.hpp" #include "com/sun/star/beans/XPropertySet.hpp" #include "com/sun/star/embed/ElementModes.hpp" #include "com/sun/star/embed/XStorage.hpp" #include "com/sun/star/embed/XTransactedObject.hpp" #include "com/sun/star/io/XActiveDataSink.hpp" #include "com/sun/star/io/XActiveDataStreamer.hpp" #include "com/sun/star/lang/IllegalAccessException.hpp" #include "com/sun/star/sdbc/XRow.hpp" #include "com/sun/star/ucb/ContentAction.hpp" #include "com/sun/star/ucb/ContentInfoAttribute.hpp" #include "com/sun/star/ucb/InsertCommandArgument.hpp" #include "com/sun/star/ucb/InteractiveBadTransferURLException.hpp" #include "com/sun/star/ucb/MissingInputStreamException.hpp" #include "com/sun/star/ucb/MissingPropertiesException.hpp" #include "com/sun/star/ucb/NameClash.hpp" #include "com/sun/star/ucb/NameClashException.hpp" #include "com/sun/star/ucb/OpenCommandArgument2.hpp" #include "com/sun/star/ucb/OpenMode.hpp" #include "com/sun/star/ucb/TransferInfo.hpp" #include "com/sun/star/ucb/UnsupportedCommandException.hpp" #include "com/sun/star/ucb/UnsupportedDataSinkException.hpp" #include "com/sun/star/ucb/UnsupportedNameClashException.hpp" #include "com/sun/star/ucb/UnsupportedOpenModeException.hpp" #include "com/sun/star/ucb/XCommandInfo.hpp" #include "com/sun/star/ucb/XPersistentPropertySet.hpp" #include "ucbhelper/cancelcommandexecution.hxx" #include "ucbhelper/contentidentifier.hxx" #include "ucbhelper/propertyvalueset.hxx" #include "tdoc_content.hxx" #include "tdoc_resultset.hxx" #include "tdoc_passwordrequest.hxx" #include "../inc/urihelper.hxx" using namespace com::sun::star; using namespace tdoc_ucp; //========================================================================= static ContentType lcl_getContentType( const rtl::OUString & rType ) { if ( rType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( TDOC_ROOT_CONTENT_TYPE ) ) ) return ROOT; else if ( rType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( TDOC_DOCUMENT_CONTENT_TYPE ) ) ) return DOCUMENT; else if ( rType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( TDOC_FOLDER_CONTENT_TYPE ) ) ) return FOLDER; else if ( rType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( TDOC_STREAM_CONTENT_TYPE ) ) ) return STREAM; else { OSL_ENSURE( sal_False, "Content::Content - unsupported content type string" ); return STREAM; } } //========================================================================= //========================================================================= // // Content Implementation. // //========================================================================= //========================================================================= // static ( "virtual" ctor ) Content* Content::create( const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, ContentProvider* pProvider, const uno::Reference< ucb::XContentIdentifier >& Identifier ) { // Fail, if resource does not exist. ContentProperties aProps; if ( !Content::loadData( pProvider, Uri( Identifier->getContentIdentifier() ), aProps ) ) return 0; return new Content( rxSMgr, pProvider, Identifier, aProps ); } //========================================================================= // static ( "virtual" ctor ) Content* Content::create( const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, ContentProvider* pProvider, const uno::Reference< ucb::XContentIdentifier >& Identifier, const ucb::ContentInfo& Info ) { if ( !Info.Type.getLength() ) return 0; if ( !Info.Type.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( TDOC_FOLDER_CONTENT_TYPE ) ) && !Info.Type.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( TDOC_STREAM_CONTENT_TYPE ) ) ) { OSL_ENSURE( sal_False, "Content::create - unsupported content type!" ); return 0; } #if 0 // Fail, if content does exist. if ( Content::hasData( pProvider, Uri( Identifier->getContentIdentifier() ) ) ) return 0; #endif return new Content( rxSMgr, pProvider, Identifier, Info ); } //========================================================================= Content::Content( const uno::Reference< lang::XMultiServiceFactory > & rxSMgr, ContentProvider * pProvider, const uno::Reference< ucb::XContentIdentifier > & Identifier, const ContentProperties & rProps ) : ContentImplHelper( rxSMgr, pProvider, Identifier ), m_aProps( rProps ), m_eState( PERSISTENT ), m_pProvider( pProvider ) { } //========================================================================= // ctor for a content just created via XContentCreator::createNewContent() Content::Content( const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, ContentProvider* pProvider, const uno::Reference< ucb::XContentIdentifier >& Identifier, const ucb::ContentInfo& Info ) : ContentImplHelper( rxSMgr, pProvider, Identifier ), m_aProps( lcl_getContentType( Info.Type ), rtl::OUString() ), // no Title (yet) m_eState( TRANSIENT ), m_pProvider( pProvider ) { } //========================================================================= // virtual Content::~Content() { } //========================================================================= // // XInterface methods. // //========================================================================= // virtual void SAL_CALL Content::acquire() throw( ) { ContentImplHelper::acquire(); } //========================================================================= // virtual void SAL_CALL Content::release() throw( ) { ContentImplHelper::release(); } //========================================================================= // virtual uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType ) throw ( uno::RuntimeException ) { uno::Any aRet = ContentImplHelper::queryInterface( rType ); if ( !aRet.hasValue() ) { aRet = cppu::queryInterface( rType, static_cast< ucb::XContentCreator * >( this ) ); if ( aRet.hasValue() ) { if ( !m_aProps.isContentCreator() ) return uno::Any(); } } return aRet; } //========================================================================= // // XTypeProvider methods. // //========================================================================= XTYPEPROVIDER_COMMON_IMPL( Content ); //========================================================================= // virtual uno::Sequence< uno::Type > SAL_CALL Content::getTypes() throw( uno::RuntimeException ) { cppu::OTypeCollection * pCollection = 0; if ( m_aProps.isContentCreator() ) { static cppu::OTypeCollection* pFolderTypes = 0; pCollection = pFolderTypes; if ( !pCollection ) { osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); pCollection = pFolderTypes; if ( !pCollection ) { static cppu::OTypeCollection aCollection( CPPU_TYPE_REF( lang::XTypeProvider ), CPPU_TYPE_REF( lang::XServiceInfo ), CPPU_TYPE_REF( lang::XComponent ), CPPU_TYPE_REF( ucb::XContent ), CPPU_TYPE_REF( ucb::XCommandProcessor ), CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ), CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ), CPPU_TYPE_REF( beans::XPropertyContainer ), CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ), CPPU_TYPE_REF( container::XChild ), CPPU_TYPE_REF( ucb::XContentCreator ) ); // !! pCollection = &aCollection; OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); pFolderTypes = pCollection; } } else { OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); } } else { static cppu::OTypeCollection* pDocumentTypes = 0; pCollection = pDocumentTypes; if ( !pCollection ) { osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); pCollection = pDocumentTypes; if ( !pCollection ) { static cppu::OTypeCollection aCollection( CPPU_TYPE_REF( lang::XTypeProvider ), CPPU_TYPE_REF( lang::XServiceInfo ), CPPU_TYPE_REF( lang::XComponent ), CPPU_TYPE_REF( ucb::XContent ), CPPU_TYPE_REF( ucb::XCommandProcessor ), CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ), CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ), CPPU_TYPE_REF( beans::XPropertyContainer ), CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ), CPPU_TYPE_REF( container::XChild ) ); pCollection = &aCollection; OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); pDocumentTypes = pCollection; } } else { OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); } } return (*pCollection).getTypes(); } //========================================================================= // // XServiceInfo methods. // //========================================================================= // virtual rtl::OUString SAL_CALL Content::getImplementationName() throw( uno::RuntimeException ) { return rtl::OUString::createFromAscii( "com.sun.star.comp.ucb.TransientDocumentsContent" ); } //========================================================================= // virtual uno::Sequence< rtl::OUString > SAL_CALL Content::getSupportedServiceNames() throw( uno::RuntimeException ) { osl::Guard< osl::Mutex > aGuard( m_aMutex ); uno::Sequence< rtl::OUString > aSNS( 1 ); if ( m_aProps.getType() == STREAM ) aSNS.getArray()[ 0 ] = rtl::OUString::createFromAscii( TDOC_STREAM_CONTENT_SERVICE_NAME ); else if ( m_aProps.getType() == FOLDER ) aSNS.getArray()[ 0 ] = rtl::OUString::createFromAscii( TDOC_FOLDER_CONTENT_SERVICE_NAME ); else if ( m_aProps.getType() == DOCUMENT ) aSNS.getArray()[ 0 ] = rtl::OUString::createFromAscii( TDOC_DOCUMENT_CONTENT_SERVICE_NAME ); else aSNS.getArray()[ 0 ] = rtl::OUString::createFromAscii( TDOC_ROOT_CONTENT_SERVICE_NAME ); return aSNS; } //========================================================================= // // XContent methods. // //========================================================================= // virtual rtl::OUString SAL_CALL Content::getContentType() throw( uno::RuntimeException ) { osl::Guard< osl::Mutex > aGuard( m_aMutex ); return m_aProps.getContentType(); } //========================================================================= // virtual uno::Reference< ucb::XContentIdentifier > SAL_CALL Content::getIdentifier() throw( uno::RuntimeException ) { { osl::Guard< osl::Mutex > aGuard( m_aMutex ); // Transient? if ( m_eState == TRANSIENT ) { // Transient contents have no identifier. return uno::Reference< ucb::XContentIdentifier >(); } } return ContentImplHelper::getIdentifier(); } //========================================================================= // // XCommandProcessor methods. // //========================================================================= // virtual uno::Any SAL_CALL Content::execute( const ucb::Command& aCommand, sal_Int32 /*CommandId*/, const uno::Reference< ucb::XCommandEnvironment >& Environment ) throw( uno::Exception, ucb::CommandAbortedException, uno::RuntimeException ) { uno::Any aRet; if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "getPropertyValues" ) ) ) { ////////////////////////////////////////////////////////////////// // getPropertyValues ////////////////////////////////////////////////////////////////// uno::Sequence< beans::Property > Properties; if ( !( aCommand.Argument >>= Properties ) ) { ucbhelper::cancelCommandExecution( uno::makeAny( lang::IllegalArgumentException( rtl::OUString::createFromAscii( "Wrong argument type!" ), static_cast< cppu::OWeakObject * >( this ), -1 ) ), Environment ); // Unreachable } aRet <<= getPropertyValues( Properties ); } else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "setPropertyValues" ) ) ) { ////////////////////////////////////////////////////////////////// // setPropertyValues ////////////////////////////////////////////////////////////////// uno::Sequence< beans::PropertyValue > aProperties; if ( !( aCommand.Argument >>= aProperties ) ) { ucbhelper::cancelCommandExecution( uno::makeAny( lang::IllegalArgumentException( rtl::OUString::createFromAscii( "Wrong argument type!" ), static_cast< cppu::OWeakObject * >( this ), -1 ) ), Environment ); // Unreachable } if ( !aProperties.getLength() ) { ucbhelper::cancelCommandExecution( uno::makeAny( lang::IllegalArgumentException( rtl::OUString::createFromAscii( "No properties!" ), static_cast< cppu::OWeakObject * >( this ), -1 ) ), Environment ); // Unreachable } aRet <<= setPropertyValues( aProperties, Environment ); } else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "getPropertySetInfo" ) ) ) { ////////////////////////////////////////////////////////////////// // getPropertySetInfo ////////////////////////////////////////////////////////////////// aRet <<= getPropertySetInfo( Environment ); } else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "getCommandInfo" ) ) ) { ////////////////////////////////////////////////////////////////// // getCommandInfo ////////////////////////////////////////////////////////////////// aRet <<= getCommandInfo( Environment ); } else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "open" ) ) ) { ////////////////////////////////////////////////////////////////// // open ////////////////////////////////////////////////////////////////// ucb::OpenCommandArgument2 aOpenCommand; if ( !( aCommand.Argument >>= aOpenCommand ) ) { ucbhelper::cancelCommandExecution( uno::makeAny( lang::IllegalArgumentException( rtl::OUString::createFromAscii( "Wrong argument type!" ), static_cast< cppu::OWeakObject * >( this ), -1 ) ), Environment ); // Unreachable } aRet = open( aOpenCommand, Environment ); } else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "insert" ) ) ) { ////////////////////////////////////////////////////////////////// // insert ( Supported by folders and streams only ) ////////////////////////////////////////////////////////////////// ContentType eType = m_aProps.getType(); if ( ( eType != FOLDER ) && ( eType != STREAM ) ) { ucbhelper::cancelCommandExecution( uno::makeAny( ucb::UnsupportedCommandException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "insert command only supported by " "folders and streams!" ) ), static_cast< cppu::OWeakObject * >( this ) ) ), Environment ); // Unreachable } #ifdef NO_STREAM_CREATION_WITHIN_DOCUMENT_ROOT if ( eType == STREAM ) { Uri aUri( m_xIdentifier->getContentIdentifier() ); Uri aParentUri( aUri.getParentUri() ); if ( aParentUri.isDocument() ) { ucbhelper::cancelCommandExecution( uno::makeAny( ucb::UnsupportedCommandException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "insert command not supported by " "streams that are direct children " "of document root!" ) ), static_cast< cppu::OWeakObject * >( this ) ) ), Environment ); // Unreachable } } #endif ucb::InsertCommandArgument aArg; if ( !( aCommand.Argument >>= aArg ) ) { ucbhelper::cancelCommandExecution( uno::makeAny( lang::IllegalArgumentException( rtl::OUString::createFromAscii( "Wrong argument type!" ), static_cast< cppu::OWeakObject * >( this ), -1 ) ), Environment ); // Unreachable } sal_Int32 nNameClash = aArg.ReplaceExisting ? ucb::NameClash::OVERWRITE : ucb::NameClash::ERROR; insert( aArg.Data, nNameClash, Environment ); } else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "delete" ) ) ) { ////////////////////////////////////////////////////////////////// // delete ( Supported by folders and streams only ) ////////////////////////////////////////////////////////////////// { osl::MutexGuard aGuard( m_aMutex ); ContentType eType = m_aProps.getType(); if ( ( eType != FOLDER ) && ( eType != STREAM ) ) { ucbhelper::cancelCommandExecution( uno::makeAny( ucb::UnsupportedCommandException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "delete command only supported by " "folders and streams!" ) ), static_cast< cppu::OWeakObject * >( this ) ) ), Environment ); // Unreachable } } sal_Bool bDeletePhysical = sal_False; aCommand.Argument >>= bDeletePhysical; destroy( bDeletePhysical, Environment ); // Remove own and all children's persistent data. if ( !removeData() ) { uno::Any aProps = uno::makeAny( beans::PropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Uri")), -1, uno::makeAny(m_xIdentifier-> getContentIdentifier()), beans::PropertyState_DIRECT_VALUE)); ucbhelper::cancelCommandExecution( ucb::IOErrorCode_CANT_WRITE, uno::Sequence< uno::Any >(&aProps, 1), Environment, rtl::OUString::createFromAscii( "Cannot remove persistent data!" ), this ); // Unreachable } // Remove own and all children's Additional Core Properties. removeAdditionalPropertySet( sal_True ); } else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "transfer" ) ) ) { ////////////////////////////////////////////////////////////////// // transfer ( Supported by document and folders only ) ////////////////////////////////////////////////////////////////// { osl::MutexGuard aGuard( m_aMutex ); ContentType eType = m_aProps.getType(); if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) ) { ucbhelper::cancelCommandExecution( uno::makeAny( ucb::UnsupportedCommandException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "transfer command only supported " "by folders and documents!" ) ), static_cast< cppu::OWeakObject * >( this ) ) ), Environment ); // Unreachable } } ucb::TransferInfo aInfo; if ( !( aCommand.Argument >>= aInfo ) ) { OSL_ENSURE( sal_False, "Wrong argument type!" ); ucbhelper::cancelCommandExecution( uno::makeAny( lang::IllegalArgumentException( rtl::OUString::createFromAscii( "Wrong argument type!" ), static_cast< cppu::OWeakObject * >( this ), -1 ) ), Environment ); // Unreachable } transfer( aInfo, Environment ); } else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "createNewContent" ) ) ) { ////////////////////////////////////////////////////////////////// // createNewContent ( Supported by document and folders only ) ////////////////////////////////////////////////////////////////// { osl::MutexGuard aGuard( m_aMutex ); ContentType eType = m_aProps.getType(); if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) ) { ucbhelper::cancelCommandExecution( uno::makeAny( ucb::UnsupportedCommandException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "createNewContent command only " "supported by folders and " "documents!" ) ), static_cast< cppu::OWeakObject * >( this ) ) ), Environment ); // Unreachable } } ucb::ContentInfo aInfo; if ( !( aCommand.Argument >>= aInfo ) ) { OSL_ENSURE( sal_False, "Wrong argument type!" ); ucbhelper::cancelCommandExecution( uno::makeAny( lang::IllegalArgumentException( rtl::OUString::createFromAscii( "Wrong argument type!" ), static_cast< cppu::OWeakObject * >( this ), -1 ) ), Environment ); // Unreachable } aRet <<= createNewContent( aInfo ); } else { ////////////////////////////////////////////////////////////////// // Unsupported command ////////////////////////////////////////////////////////////////// ucbhelper::cancelCommandExecution( uno::makeAny( ucb::UnsupportedCommandException( rtl::OUString(), static_cast< cppu::OWeakObject * >( this ) ) ), Environment ); // Unreachable } return aRet; } //========================================================================= // virtual void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ ) throw( uno::RuntimeException ) { } //========================================================================= // // XContentCreator methods. // //========================================================================= // virtual uno::Sequence< ucb::ContentInfo > SAL_CALL Content::queryCreatableContentsInfo() throw( uno::RuntimeException ) { return m_aProps.getCreatableContentsInfo(); } //========================================================================= // virtual uno::Reference< ucb::XContent > SAL_CALL Content::createNewContent( const ucb::ContentInfo& Info ) throw( uno::RuntimeException ) { if ( m_aProps.isContentCreator() ) { osl::Guard< osl::Mutex > aGuard( m_aMutex ); if ( !Info.Type.getLength() ) return uno::Reference< ucb::XContent >(); sal_Bool bCreateFolder = Info.Type.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( TDOC_FOLDER_CONTENT_TYPE ) ); #ifdef NO_STREAM_CREATION_WITHIN_DOCUMENT_ROOT // streams cannot be created as direct children of document root if ( !bCreateFolder && ( m_aProps.getType() == DOCUMENT ) ) { OSL_ENSURE( sal_False, "Content::createNewContent - streams cannot be " "created as direct children of document root!" ); return uno::Reference< ucb::XContent >(); } #endif if ( !bCreateFolder && !Info.Type.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( TDOC_STREAM_CONTENT_TYPE ) ) ) { OSL_ENSURE( sal_False, "Content::createNewContent - unsupported type!" ); return uno::Reference< ucb::XContent >(); } rtl::OUString aURL = m_xIdentifier->getContentIdentifier(); OSL_ENSURE( aURL.getLength() > 0, "Content::createNewContent - empty identifier!" ); if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() ) aURL += rtl::OUString::createFromAscii( "/" ); if ( bCreateFolder ) aURL += rtl::OUString::createFromAscii( "New_Folder" ); else aURL += rtl::OUString::createFromAscii( "New_Stream" ); uno::Reference< ucb::XContentIdentifier > xId = new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL ); return create( m_xSMgr, m_pProvider, xId, Info ); } else { OSL_ENSURE( sal_False, "createNewContent called on non-contentcreator object!" ); return uno::Reference< ucb::XContent >(); } } //========================================================================= // virtual rtl::OUString Content::getParentURL() { osl::Guard< osl::Mutex > aGuard( m_aMutex ); Uri aUri( m_xIdentifier->getContentIdentifier() ); return aUri.getParentUri(); } //========================================================================= uno::Reference< ucb::XContentIdentifier > Content::makeNewIdentifier( const rtl::OUString& rTitle ) { osl::Guard< osl::Mutex > aGuard( m_aMutex ); // Assemble new content identifier... Uri aUri( m_xIdentifier->getContentIdentifier() ); rtl::OUStringBuffer aNewURL = aUri.getParentUri(); aNewURL.append( ::ucb_impl::urihelper::encodeSegment( rTitle ) ); return uno::Reference< ucb::XContentIdentifier >( new ::ucbhelper::ContentIdentifier( m_xSMgr, aNewURL.makeStringAndClear() ) ); } //========================================================================= void Content::queryChildren( ContentRefList& rChildren ) { osl::Guard< osl::Mutex > aGuard( m_aMutex ); // Only folders (root, documents, folders) have children. if ( !m_aProps.getIsFolder() ) return; // Obtain a list with a snapshot of all currently instanciated contents // from provider and extract the contents which are direct children // of this content. ::ucbhelper::ContentRefList aAllContents; m_xProvider->queryExistingContents( aAllContents ); rtl::OUString aURL = m_xIdentifier->getContentIdentifier(); sal_Int32 nURLPos = aURL.lastIndexOf( '/' ); if ( nURLPos != ( aURL.getLength() - 1 ) ) { // No trailing slash found. Append. aURL += rtl::OUString::createFromAscii( "/" ); } sal_Int32 nLen = aURL.getLength(); ::ucbhelper::ContentRefList::const_iterator it = aAllContents.begin(); ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end(); while ( it != end ) { ::ucbhelper::ContentImplHelperRef xChild = (*it); rtl::OUString aChildURL = xChild->getIdentifier()->getContentIdentifier(); // Is aURL a prefix of aChildURL? if ( ( aChildURL.getLength() > nLen ) && ( aChildURL.compareTo( aURL, nLen ) == 0 ) ) { sal_Int32 nPos = nLen; nPos = aChildURL.indexOf( '/', nPos ); if ( ( nPos == -1 ) || ( nPos == ( aChildURL.getLength() - 1 ) ) ) { // No further slashes / only a final slash. It's a child! rChildren.push_back( ContentRef( static_cast< Content * >( xChild.get() ) ) ); } } ++it; } } //========================================================================= sal_Bool Content::exchangeIdentity( const uno::Reference< ucb::XContentIdentifier >& xNewId ) { if ( !xNewId.is() ) return sal_False; osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); uno::Reference< ucb::XContent > xThis = this; // Already persistent? if ( m_eState != PERSISTENT ) { OSL_ENSURE( sal_False, "Content::exchangeIdentity - Not persistent!" ); return sal_False; } // Only folders and streams can be renamed -> exchange identity. ContentType eType = m_aProps.getType(); if ( ( eType == ROOT ) || ( eType == DOCUMENT ) ) { OSL_ENSURE( sal_False, "Content::exchangeIdentity - " "Not supported by root or document!" ); return sal_False; } // Exchange own identitity. // Fail, if a content with given id already exists. if ( !hasData( Uri( xNewId->getContentIdentifier() ) ) ) { rtl::OUString aOldURL = m_xIdentifier->getContentIdentifier(); aGuard.clear(); if ( exchange( xNewId ) ) { if ( eType == FOLDER ) { // Process instanciated children... ContentRefList aChildren; queryChildren( aChildren ); ContentRefList::const_iterator it = aChildren.begin(); ContentRefList::const_iterator end = aChildren.end(); while ( it != end ) { ContentRef xChild = (*it); // Create new content identifier for the child... uno::Reference< ucb::XContentIdentifier > xOldChildId = xChild->getIdentifier(); rtl::OUString aOldChildURL = xOldChildId->getContentIdentifier(); rtl::OUString aNewChildURL = aOldChildURL.replaceAt( 0, aOldURL.getLength(), xNewId->getContentIdentifier() ); uno::Reference< ucb::XContentIdentifier > xNewChildId = new ::ucbhelper::ContentIdentifier( m_xSMgr, aNewChildURL ); if ( !xChild->exchangeIdentity( xNewChildId ) ) return sal_False; ++it; } } return sal_True; } } OSL_ENSURE( sal_False, "Content::exchangeIdentity - " "Panic! Cannot exchange identity!" ); return sal_False; } //========================================================================= // static uno::Reference< sdbc::XRow > Content::getPropertyValues( const uno::Reference< lang::XMultiServiceFactory >& rSMgr, const uno::Sequence< beans::Property >& rProperties, ContentProvider* pProvider, const rtl::OUString& rContentId ) { ContentProperties aData; if ( loadData( pProvider, rContentId, aData ) ) { return getPropertyValues( rSMgr, rProperties, aData, pProvider, rContentId ); } else { rtl::Reference< ::ucbhelper::PropertyValueSet > xRow = new ::ucbhelper::PropertyValueSet( rSMgr ); sal_Int32 nCount = rProperties.getLength(); if ( nCount ) { const beans::Property* pProps = rProperties.getConstArray(); for ( sal_Int32 n = 0; n < nCount; ++n ) xRow->appendVoid( pProps[ n ] ); } return uno::Reference< sdbc::XRow >( xRow.get() ); } } //========================================================================= // static uno::Reference< sdbc::XRow > Content::getPropertyValues( const uno::Reference< lang::XMultiServiceFactory >& rSMgr, const uno::Sequence< beans::Property >& rProperties, const ContentProperties& rData, ContentProvider* pProvider, const rtl::OUString& rContentId ) { // Note: Empty sequence means "get values of all supported properties". rtl::Reference< ::ucbhelper::PropertyValueSet > xRow = new ::ucbhelper::PropertyValueSet( rSMgr ); sal_Int32 nCount = rProperties.getLength(); if ( nCount ) { uno::Reference< beans::XPropertySet > xAdditionalPropSet; sal_Bool bTriedToGetAdditonalPropSet = sal_False; const beans::Property* pProps = rProperties.getConstArray(); for ( sal_Int32 n = 0; n < nCount; ++n ) { const beans::Property& rProp = pProps[ n ]; // Process Core properties. if ( rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) ) { xRow->appendString ( rProp, rData.getContentType() ); } else if ( rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) { xRow->appendString ( rProp, rData.getTitle() ); } else if ( rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) ) { xRow->appendBoolean( rProp, rData.getIsDocument() ); } else if ( rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) ) { xRow->appendBoolean( rProp, rData.getIsFolder() ); } else if ( rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) ) { xRow->appendObject( rProp, uno::makeAny( rData.getCreatableContentsInfo() ) ); } else if ( rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Storage" ) ) ) { // Storage is only supported by folders. ContentType eType = rData.getType(); if ( eType == FOLDER ) xRow->appendObject( rProp, uno::makeAny( pProvider->queryStorageClone( rContentId ) ) ); else xRow->appendVoid( rProp ); } else if ( rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "DocumentModel" ) ) ) { // DocumentModel is only supported by documents. ContentType eType = rData.getType(); if ( eType == DOCUMENT ) xRow->appendObject( rProp, uno::makeAny( pProvider->queryDocumentModel( rContentId ) ) ); else xRow->appendVoid( rProp ); } else { // Not a Core Property! Maybe it's an Additional Core Property?! if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() ) { xAdditionalPropSet = uno::Reference< beans::XPropertySet >( pProvider->getAdditionalPropertySet( rContentId, sal_False ), uno::UNO_QUERY ); bTriedToGetAdditonalPropSet = sal_True; } if ( xAdditionalPropSet.is() ) { if ( !xRow->appendPropertySetValue( xAdditionalPropSet, rProp ) ) { // Append empty entry. xRow->appendVoid( rProp ); } } else { // Append empty entry. xRow->appendVoid( rProp ); } } } } else { // Append all Core Properties. xRow->appendString ( beans::Property( rtl::OUString::createFromAscii( "ContentType" ), -1, getCppuType( static_cast< const rtl::OUString * >( 0 ) ), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), rData.getContentType() ); ContentType eType = rData.getType(); xRow->appendString ( beans::Property( rtl::OUString::createFromAscii( "Title" ), -1, getCppuType( static_cast< const rtl::OUString * >( 0 ) ), // Title is read-only for root and documents. beans::PropertyAttribute::BOUND || ( ( eType == ROOT ) || ( eType == DOCUMENT ) ) ? beans::PropertyAttribute::READONLY : 0 ), rData.getTitle() ); xRow->appendBoolean( beans::Property( rtl::OUString::createFromAscii( "IsDocument" ), -1, getCppuBooleanType(), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), rData.getIsDocument() ); xRow->appendBoolean( beans::Property( rtl::OUString::createFromAscii( "IsFolder" ), -1, getCppuBooleanType(), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), rData.getIsFolder() ); xRow->appendObject( beans::Property( rtl::OUString::createFromAscii( "CreatableContentsInfo" ), -1, getCppuType( static_cast< const uno::Sequence< ucb::ContentInfo > * >( 0 ) ), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), uno::makeAny( rData.getCreatableContentsInfo() ) ); // Storage is only supported by folders. if ( eType == FOLDER ) xRow->appendObject( beans::Property( rtl::OUString::createFromAscii( "Storage" ), -1, getCppuType( static_cast< const uno::Reference< embed::XStorage > * >( 0 ) ), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), uno::makeAny( pProvider->queryStorageClone( rContentId ) ) ); // DocumentModel is only supported by documents. if ( eType == DOCUMENT ) xRow->appendObject( beans::Property( rtl::OUString::createFromAscii( "DocumentModel" ), -1, getCppuType( static_cast< const uno::Reference< frame::XModel > * >( 0 ) ), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), uno::makeAny( pProvider->queryDocumentModel( rContentId ) ) ); // Append all Additional Core Properties. uno::Reference< beans::XPropertySet > xSet( pProvider->getAdditionalPropertySet( rContentId, sal_False ), uno::UNO_QUERY ); xRow->appendPropertySet( xSet ); } return uno::Reference< sdbc::XRow >( xRow.get() ); } //========================================================================= uno::Reference< sdbc::XRow > Content::getPropertyValues( const uno::Sequence< beans::Property >& rProperties ) { osl::Guard< osl::Mutex > aGuard( m_aMutex ); return getPropertyValues( m_xSMgr, rProperties, m_aProps, m_pProvider, m_xIdentifier->getContentIdentifier() ); } //========================================================================= uno::Sequence< uno::Any > Content::setPropertyValues( const uno::Sequence< beans::PropertyValue >& rValues, const uno::Reference< ucb::XCommandEnvironment > & xEnv ) throw( uno::Exception ) { osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); uno::Sequence< uno::Any > aRet( rValues.getLength() ); uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() ); sal_Int32 nChanged = 0; beans::PropertyChangeEvent aEvent; aEvent.Source = static_cast< cppu::OWeakObject * >( this ); aEvent.Further = sal_False; // aEvent.PropertyName = aEvent.PropertyHandle = -1; // aEvent.OldValue = // aEvent.NewValue = const beans::PropertyValue* pValues = rValues.getConstArray(); sal_Int32 nCount = rValues.getLength(); uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet; sal_Bool bTriedToGetAdditonalPropSet = sal_False; sal_Bool bExchange = sal_False; rtl::OUString aOldTitle; sal_Int32 nTitlePos = -1; for ( sal_Int32 n = 0; n < nCount; ++n ) { const beans::PropertyValue& rValue = pValues[ n ]; if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) ) { // Read-only property! aRet[ n ] <<= lang::IllegalAccessException( rtl::OUString::createFromAscii( "Property is read-only!" ), static_cast< cppu::OWeakObject * >( this ) ); } else if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) ) { // Read-only property! aRet[ n ] <<= lang::IllegalAccessException( rtl::OUString::createFromAscii( "Property is read-only!" ), static_cast< cppu::OWeakObject * >( this ) ); } else if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) ) { // Read-only property! aRet[ n ] <<= lang::IllegalAccessException( rtl::OUString::createFromAscii( "Property is read-only!" ), static_cast< cppu::OWeakObject * >( this ) ); } else if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) ) { // Read-only property! aRet[ n ] <<= lang::IllegalAccessException( rtl::OUString::createFromAscii( "Property is read-only!" ), static_cast< cppu::OWeakObject * >( this ) ); } else if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) { // Title is read-only for root and documents. ContentType eType = m_aProps.getType(); if ( ( eType == ROOT ) || ( eType == DOCUMENT ) ) { aRet[ n ] <<= lang::IllegalAccessException( rtl::OUString::createFromAscii( "Property is read-only!" ), static_cast< cppu::OWeakObject * >( this ) ); } else { rtl::OUString aNewValue; if ( rValue.Value >>= aNewValue ) { // No empty titles! if ( aNewValue.getLength() > 0 ) { if ( aNewValue != m_aProps.getTitle() ) { // modified title -> modified URL -> exchange ! if ( m_eState == PERSISTENT ) bExchange = sal_True; aOldTitle = m_aProps.getTitle(); m_aProps.setTitle( aNewValue ); // property change event will be sent later... // remember position within sequence of values // (for error handling). nTitlePos = n; } } else { aRet[ n ] <<= lang::IllegalArgumentException( rtl::OUString::createFromAscii( "Empty Title not allowed!" ), static_cast< cppu::OWeakObject * >( this ), -1 ); } } else { aRet[ n ] <<= beans::IllegalTypeException( rtl::OUString::createFromAscii( "Title Property value has wrong type!" ), static_cast< cppu::OWeakObject * >( this ) ); } } } else if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Storage" ) ) ) { ContentType eType = m_aProps.getType(); if ( eType == FOLDER ) { aRet[ n ] <<= lang::IllegalAccessException( rtl::OUString::createFromAscii( "Property is read-only!" ), static_cast< cppu::OWeakObject * >( this ) ); } else { // Storage is only supported by folders. aRet[ n ] <<= beans::UnknownPropertyException( rtl::OUString::createFromAscii( "Storage property only supported by folders" ), static_cast< cppu::OWeakObject * >( this ) ); } } else if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "DocumentModel" ) ) ) { ContentType eType = m_aProps.getType(); if ( eType == DOCUMENT ) { aRet[ n ] <<= lang::IllegalAccessException( rtl::OUString::createFromAscii( "Property is read-only!" ), static_cast< cppu::OWeakObject * >( this ) ); } else { // Storage is only supported by folders. aRet[ n ] <<= beans::UnknownPropertyException( rtl::OUString::createFromAscii( "DocumentModel property only supported by " "documents" ), static_cast< cppu::OWeakObject * >( this ) ); } } else { // Not a Core Property! Maybe it's an Additional Core Property?! if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() ) { xAdditionalPropSet = getAdditionalPropertySet( sal_False ); bTriedToGetAdditonalPropSet = sal_True; } if ( xAdditionalPropSet.is() ) { try { uno::Any aOldValue = xAdditionalPropSet->getPropertyValue( rValue.Name ); if ( aOldValue != rValue.Value ) { xAdditionalPropSet->setPropertyValue( rValue.Name, rValue.Value ); aEvent.PropertyName = rValue.Name; aEvent.OldValue = aOldValue; aEvent.NewValue = rValue.Value; aChanges.getArray()[ nChanged ] = aEvent; nChanged++; } } catch ( beans::UnknownPropertyException const & e ) { aRet[ n ] <<= e; } catch ( lang::WrappedTargetException const & e ) { aRet[ n ] <<= e; } catch ( beans::PropertyVetoException const & e ) { aRet[ n ] <<= e; } catch ( lang::IllegalArgumentException const & e ) { aRet[ n ] <<= e; } } else { aRet[ n ] <<= uno::Exception( rtl::OUString::createFromAscii( "No property set for storing the value!" ), static_cast< cppu::OWeakObject * >( this ) ); } } } if ( bExchange ) { uno::Reference< ucb::XContentIdentifier > xOldId = m_xIdentifier; uno::Reference< ucb::XContentIdentifier > xNewId = makeNewIdentifier( m_aProps.getTitle() ); aGuard.clear(); if ( exchangeIdentity( xNewId ) ) { // Adapt persistent data. renameData( xOldId, xNewId ); // Adapt Additional Core Properties. renameAdditionalPropertySet( xOldId->getContentIdentifier(), xNewId->getContentIdentifier(), sal_True ); } else { // Roll-back. m_aProps.setTitle( aOldTitle ); aOldTitle = rtl::OUString(); // Set error . aRet[ nTitlePos ] <<= uno::Exception( rtl::OUString::createFromAscii( "Exchange failed!" ), static_cast< cppu::OWeakObject * >( this ) ); } } if ( aOldTitle.getLength() ) { aEvent.PropertyName = rtl::OUString::createFromAscii( "Title" ); aEvent.OldValue = uno::makeAny( aOldTitle ); aEvent.NewValue = uno::makeAny( m_aProps.getTitle() ); aChanges.getArray()[ nChanged ] = aEvent; nChanged++; } if ( nChanged > 0 ) { // Save changes, if content was already made persistent. if ( !bExchange && ( m_eState == PERSISTENT ) ) { if ( !storeData( uno::Reference< io::XInputStream >(), xEnv ) ) { uno::Any aProps = uno::makeAny( beans::PropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Uri")), -1, uno::makeAny(m_xIdentifier-> getContentIdentifier()), beans::PropertyState_DIRECT_VALUE)); ucbhelper::cancelCommandExecution( ucb::IOErrorCode_CANT_WRITE, uno::Sequence< uno::Any >(&aProps, 1), xEnv, rtl::OUString::createFromAscii( "Cannot store persistent data!" ), this ); // Unreachable } } aChanges.realloc( nChanged ); aGuard.clear(); notifyPropertiesChange( aChanges ); } return aRet; } //========================================================================= uno::Any Content::open( const ucb::OpenCommandArgument2& rArg, const uno::Reference< ucb::XCommandEnvironment >& xEnv ) throw( uno::Exception ) { if ( rArg.Mode == ucb::OpenMode::ALL || rArg.Mode == ucb::OpenMode::FOLDERS || rArg.Mode == ucb::OpenMode::DOCUMENTS ) { ////////////////////////////////////////////////////////////////// // open command for a folder content ////////////////////////////////////////////////////////////////// uno::Reference< ucb::XDynamicResultSet > xSet = new DynamicResultSet( m_xSMgr, this, rArg ); return uno::makeAny( xSet ); } else { ////////////////////////////////////////////////////////////////// // open command for a document content ////////////////////////////////////////////////////////////////// if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) || ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) ) { // Currently(?) unsupported. ucbhelper::cancelCommandExecution( uno::makeAny( ucb::UnsupportedOpenModeException( rtl::OUString(), static_cast< cppu::OWeakObject * >( this ), sal_Int16( rArg.Mode ) ) ), xEnv ); // Unreachable } osl::Guard< osl::Mutex > aGuard( m_aMutex ); rtl::OUString aURL = m_xIdentifier->getContentIdentifier(); uno::Reference< io::XActiveDataStreamer > xDataStreamer( rArg.Sink, uno::UNO_QUERY ); if ( xDataStreamer.is() ) { // May throw CommandFailedException, DocumentPasswordRequest! uno::Reference< io::XStream > xStream = getStream( xEnv ); if ( !xStream.is() ) { // No interaction if we are not persistent! uno::Any aProps = uno::makeAny( beans::PropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Uri")), -1, uno::makeAny(m_xIdentifier-> getContentIdentifier()), beans::PropertyState_DIRECT_VALUE)); ucbhelper::cancelCommandExecution( ucb::IOErrorCode_CANT_READ, uno::Sequence< uno::Any >(&aProps, 1), m_eState == PERSISTENT ? xEnv : uno::Reference< ucb::XCommandEnvironment >(), rtl::OUString::createFromAscii( "Got no data stream!" ), this ); // Unreachable } // Done. xDataStreamer->setStream( xStream ); } else { uno::Reference< io::XOutputStream > xOut( rArg.Sink, uno::UNO_QUERY ); if ( xOut.is() ) { // PUSH: write data into xOut // May throw CommandFailedException, DocumentPasswordRequest! uno::Reference< io::XInputStream > xIn = getInputStream( xEnv ); if ( !xIn.is() ) { // No interaction if we are not persistent! uno::Any aProps = uno::makeAny( beans::PropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Uri")), -1, uno::makeAny(m_xIdentifier-> getContentIdentifier()), beans::PropertyState_DIRECT_VALUE)); ucbhelper::cancelCommandExecution( ucb::IOErrorCode_CANT_READ, uno::Sequence< uno::Any >(&aProps, 1), m_eState == PERSISTENT ? xEnv : uno::Reference< ucb::XCommandEnvironment >(), rtl::OUString::createFromAscii( "Got no data stream!" ), this ); // Unreachable } try { uno::Sequence< sal_Int8 > aBuffer; sal_Int32 nRead = xIn->readSomeBytes( aBuffer, 65536 ); while ( nRead > 0 ) { aBuffer.realloc( nRead ); xOut->writeBytes( aBuffer ); aBuffer.realloc( 0 ); nRead = xIn->readSomeBytes( aBuffer, 65536 ); } xOut->closeOutput(); } catch ( io::NotConnectedException const & ) { // closeOutput, readSomeBytes, writeBytes } catch ( io::BufferSizeExceededException const & ) { // closeOutput, readSomeBytes, writeBytes } catch ( io::IOException const & ) { // closeOutput, readSomeBytes, writeBytes } } else { uno::Reference< io::XActiveDataSink > xDataSink( rArg.Sink, uno::UNO_QUERY ); if ( xDataSink.is() ) { // PULL: wait for client read // May throw CommandFailedException, DocumentPasswordRequest! uno::Reference< io::XInputStream > xIn = getInputStream( xEnv ); if ( !xIn.is() ) { // No interaction if we are not persistent! uno::Any aProps = uno::makeAny( beans::PropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Uri")), -1, uno::makeAny(m_xIdentifier-> getContentIdentifier()), beans::PropertyState_DIRECT_VALUE)); ucbhelper::cancelCommandExecution( ucb::IOErrorCode_CANT_READ, uno::Sequence< uno::Any >(&aProps, 1), m_eState == PERSISTENT ? xEnv : uno::Reference< ucb::XCommandEnvironment >(), rtl::OUString::createFromAscii( "Got no data stream!" ), this ); // Unreachable } // Done. xDataSink->setInputStream( xIn ); } else { ucbhelper::cancelCommandExecution( uno::makeAny( ucb::UnsupportedDataSinkException( rtl::OUString(), static_cast< cppu::OWeakObject * >( this ), rArg.Sink ) ), xEnv ); // Unreachable } } } } return uno::Any(); } //========================================================================= void Content::insert( const uno::Reference< io::XInputStream >& xData, sal_Int32 nNameClashResolve, const uno::Reference< ucb::XCommandEnvironment > & xEnv ) throw( uno::Exception ) { osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); ContentType eType = m_aProps.getType(); OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ), "insert command only supported by streams and folders!" ); Uri aUri( m_xIdentifier->getContentIdentifier() ); #ifdef NO_STREAM_CREATION_WITHIN_DOCUMENT_ROOT #if OSL_DEBUG_LEVEL > 0 if ( eType == STREAM ) { Uri aParentUri( aUri.getParentUri() ); OSL_ENSURE( !aParentUri.isDocument(), "insert command not supported by streams that are direct " "children of document root!" ); } #endif #endif // Check, if all required properties were set. if ( eType == FOLDER ) { // Required: Title if ( m_aProps.getTitle().getLength() == 0 ) m_aProps.setTitle( aUri.getDecodedName() ); } else // stream { // Required: data if ( !xData.is() ) { ucbhelper::cancelCommandExecution( uno::makeAny( ucb::MissingInputStreamException( rtl::OUString(), static_cast< cppu::OWeakObject * >( this ) ) ), xEnv ); // Unreachable } // Required: Title if ( m_aProps.getTitle().getLength() == 0 ) m_aProps.setTitle( aUri.getDecodedName() ); } rtl::OUStringBuffer aNewURL = aUri.getParentUri(); aNewURL.append( m_aProps.getTitle() ); Uri aNewUri( aNewURL.makeStringAndClear() ); // Handle possible name clash... switch ( nNameClashResolve ) { // fail. case ucb::NameClash::ERROR: if ( hasData( aNewUri ) ) { ucbhelper::cancelCommandExecution( uno::makeAny( ucb::NameClashException( rtl::OUString(), static_cast< cppu::OWeakObject * >( this ), task::InteractionClassification_ERROR, m_aProps.getTitle() ) ), xEnv ); // Unreachable } break; // replace (possibly) existing object. case ucb::NameClash::OVERWRITE: break; // "invent" a new valid title. case ucb::NameClash::RENAME: if ( hasData( aNewUri ) ) { sal_Int32 nTry = 0; do { rtl::OUStringBuffer aNew = aNewUri.getUri(); aNew.appendAscii( "_" ); aNew.append( rtl::OUString::valueOf( ++nTry ) ); aNewUri.setUri( aNew.makeStringAndClear() ); } while ( hasData( aNewUri ) && ( nTry < 1000 ) ); if ( nTry == 1000 ) { ucbhelper::cancelCommandExecution( uno::makeAny( ucb::UnsupportedNameClashException( rtl::OUString::createFromAscii( "Unable to resolve name clash!" ), static_cast< cppu::OWeakObject * >( this ), nNameClashResolve ) ), xEnv ); // Unreachable } else { rtl::OUStringBuffer aNewTitle = m_aProps.getTitle(); aNewTitle.appendAscii( "_" ); aNewTitle.append( rtl::OUString::valueOf( ++nTry ) ); m_aProps.setTitle( aNewTitle.makeStringAndClear() ); } } break; case ucb::NameClash::KEEP: // deprecated case ucb::NameClash::ASK: default: if ( hasData( aNewUri ) ) { ucbhelper::cancelCommandExecution( uno::makeAny( ucb::UnsupportedNameClashException( rtl::OUString(), static_cast< cppu::OWeakObject * >( this ), nNameClashResolve ) ), xEnv ); // Unreachable } break; } // Identifier changed? sal_Bool bNewId = ( aUri != aNewUri ); if ( bNewId ) { m_xIdentifier = new ::ucbhelper::ContentIdentifier( m_xSMgr, aNewUri.getUri() ); } if ( !storeData( xData, xEnv ) ) { uno::Any aProps = uno::makeAny(beans::PropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Uri")), -1, uno::makeAny(m_xIdentifier-> getContentIdentifier()), beans::PropertyState_DIRECT_VALUE)); ucbhelper::cancelCommandExecution( ucb::IOErrorCode_CANT_WRITE, uno::Sequence< uno::Any >(&aProps, 1), xEnv, rtl::OUString::createFromAscii( "Cannot store persistent data!" ), this ); // Unreachable } m_eState = PERSISTENT; if ( bNewId ) { //loadData( m_pProvider, m_aUri, m_aProps ); aGuard.clear(); inserted(); } } //========================================================================= void Content::destroy( sal_Bool bDeletePhysical, const uno::Reference< ucb::XCommandEnvironment > & xEnv ) throw( uno::Exception ) { // @@@ take care about bDeletePhysical -> trashcan support osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); ContentType eType = m_aProps.getType(); OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ), "delete command only supported by streams and folders!" ); uno::Reference< ucb::XContent > xThis = this; // Persistent? if ( m_eState != PERSISTENT ) { ucbhelper::cancelCommandExecution( uno::makeAny( ucb::UnsupportedCommandException( rtl::OUString::createFromAscii( "Not persistent!" ), static_cast< cppu::OWeakObject * >( this ) ) ), xEnv ); // Unreachable } m_eState = DEAD; aGuard.clear(); deleted(); if ( eType == FOLDER ) { // Process instanciated children... ContentRefList aChildren; queryChildren( aChildren ); ContentRefList::const_iterator it = aChildren.begin(); ContentRefList::const_iterator end = aChildren.end(); while ( it != end ) { (*it)->destroy( bDeletePhysical, xEnv ); ++it; } } } //========================================================================= void Content::notifyDocumentClosed() { osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); m_eState = DEAD; // @@@ anything else to reset or such? // callback follows! aGuard.clear(); // Propagate destruction to content event listeners // Remove this from provider's content list. deleted(); } //========================================================================= uno::Reference< ucb::XContent > Content::queryChildContent( const rtl::OUString & rRelativeChildUri ) { osl::Guard< osl::Mutex > aGuard( m_aMutex ); const rtl::OUString aMyId = getIdentifier()->getContentIdentifier(); rtl::OUStringBuffer aBuf( aMyId ); if ( aMyId.getStr()[ aMyId.getLength() - 1 ] != sal_Unicode( '/' ) ) aBuf.appendAscii( "/" ); if ( rRelativeChildUri.getStr()[ 0 ] != sal_Unicode( '/' ) ) aBuf.append( rRelativeChildUri ); else aBuf.append( rRelativeChildUri.copy( 1 ) ); uno::Reference< ucb::XContentIdentifier > xChildId = new ::ucbhelper::ContentIdentifier( m_xSMgr, aBuf.makeStringAndClear() ); uno::Reference< ucb::XContent > xChild; try { xChild = m_pProvider->queryContent( xChildId ); } catch ( ucb::IllegalIdentifierException const & ) { // handled below. } OSL_ENSURE( xChild.is(), "Content::queryChildContent - unable to create child content!" ); return xChild; } //========================================================================= void Content::notifyChildRemoved( const rtl::OUString & rRelativeChildUri ) { osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); // Ugly! Need to create child content object, just to fill event properly. uno::Reference< ucb::XContent > xChild = queryChildContent( rRelativeChildUri ); if ( xChild.is() ) { // callback follows! aGuard.clear(); // Notify "REMOVED" event. ucb::ContentEvent aEvt( static_cast< cppu::OWeakObject * >( this ), ucb::ContentAction::REMOVED, xChild, getIdentifier() ); notifyContentEvent( aEvt ); } } //========================================================================= void Content::notifyChildInserted( const rtl::OUString & rRelativeChildUri ) { osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); // Ugly! Need to create child content object, just to fill event properly. uno::Reference< ucb::XContent > xChild = queryChildContent( rRelativeChildUri ); if ( xChild.is() ) { // callback follows! aGuard.clear(); // Notify "INSERTED" event. ucb::ContentEvent aEvt( static_cast< cppu::OWeakObject * >( this ), ucb::ContentAction::INSERTED, xChild, getIdentifier() ); notifyContentEvent( aEvt ); } } //========================================================================= void Content::transfer( const ucb::TransferInfo& rInfo, const uno::Reference< ucb::XCommandEnvironment > & xEnv ) throw( uno::Exception ) { osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); // Persistent? if ( m_eState != PERSISTENT ) { ucbhelper::cancelCommandExecution( uno::makeAny( ucb::UnsupportedCommandException( rtl::OUString::createFromAscii( "Not persistent!" ), static_cast< cppu::OWeakObject * >( this ) ) ), xEnv ); // Unreachable } // Does source URI scheme match? Only vnd.sun.star.tdoc is supported. if ( ( rInfo.SourceURL.getLength() < TDOC_URL_SCHEME_LENGTH + 2 ) ) { // Invalid length (to short). ucbhelper::cancelCommandExecution( uno::makeAny( ucb::InteractiveBadTransferURLException( rtl::OUString(), static_cast< cppu::OWeakObject * >( this ) ) ), xEnv ); // Unreachable } rtl::OUString aScheme = rInfo.SourceURL.copy( 0, TDOC_URL_SCHEME_LENGTH + 2 ) .toAsciiLowerCase(); if ( !aScheme.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( TDOC_URL_SCHEME ":/" ) ) ) { // Invalid scheme. ucbhelper::cancelCommandExecution( uno::makeAny( ucb::InteractiveBadTransferURLException( rtl::OUString(), static_cast< cppu::OWeakObject * >( this ) ) ), xEnv ); // Unreachable } // Does source URI describe a tdoc folder or stream? Uri aSourceUri( rInfo.SourceURL ); if ( !aSourceUri.isValid() ) { ucbhelper::cancelCommandExecution( uno::makeAny( lang::IllegalArgumentException( rtl::OUString::createFromAscii( "Invalid source URI! Syntax!" ), static_cast< cppu::OWeakObject * >( this ), -1 ) ), xEnv ); // Unreachable } if ( aSourceUri.isRoot() || aSourceUri.isDocument() ) { ucbhelper::cancelCommandExecution( uno::makeAny( lang::IllegalArgumentException( rtl::OUString::createFromAscii( "Invalid source URI! " "Must describe a folder or stream!" ), static_cast< cppu::OWeakObject * >( this ), -1 ) ), xEnv ); // Unreachable } // Is source not a parent of me / not me? rtl::OUString aId = m_xIdentifier->getContentIdentifier(); sal_Int32 nPos = aId.lastIndexOf( '/' ); if ( nPos != ( aId.getLength() - 1 ) ) { // No trailing slash found. Append. aId += rtl::OUString::createFromAscii( "/" ); } if ( rInfo.SourceURL.getLength() <= aId.getLength() ) { if ( aId.compareTo( rInfo.SourceURL, rInfo.SourceURL.getLength() ) == 0 ) { uno::Any aProps = uno::makeAny(beans::PropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Uri")), -1, uno::makeAny( rInfo.SourceURL ), beans::PropertyState_DIRECT_VALUE)); ucbhelper::cancelCommandExecution( ucb::IOErrorCode_RECURSIVE, uno::Sequence< uno::Any >(&aProps, 1), xEnv, rtl::OUString::createFromAscii( "Target is equal to or is a child of source!" ), this ); // Unreachable } } #ifdef NO_STREAM_CREATION_WITHIN_DOCUMENT_ROOT if ( m_aProps.getType() == DOCUMENT ) { bool bOK = false; uno::Reference< embed::XStorage > xStorage = m_pProvider->queryStorage( aSourceUri.getParentUri(), READ_WRITE_NOCREATE ); if ( xStorage.is() ) { try { if ( xStorage->isStreamElement( aSourceUri.getDecodedName() ) ) { ucbhelper::cancelCommandExecution( uno::makeAny( lang::IllegalArgumentException( rtl::OUString::createFromAscii( "Invalid source URI! " "Streams cannot be created as " "children of document root!" ), static_cast< cppu::OWeakObject * >( this ), -1 ) ), xEnv ); // Unreachable } bOK = true; } catch ( container::NoSuchElementException const & ) { // handled below. } catch ( lang::IllegalArgumentException const & ) { // handled below. } catch ( embed::InvalidStorageException const & ) { // handled below. } } if ( !bOK ) { ucbhelper::cancelCommandExecution( uno::makeAny( lang::IllegalArgumentException( rtl::OUString::createFromAscii( "Invalid source URI! " "Unabale to determine source type!" ), static_cast< cppu::OWeakObject * >( this ), -1 ) ), xEnv ); // Unreachable } } #endif ///////////////////////////////////////////////////////////////////////// // Copy data. ///////////////////////////////////////////////////////////////////////// rtl::OUString aNewName( rInfo.NewTitle.getLength() > 0 ? rInfo.NewTitle : aSourceUri.getDecodedName() ); if ( !copyData( aSourceUri, aNewName ) ) { uno::Any aProps = uno::makeAny( beans::PropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Uri")), -1, uno::makeAny( rInfo.SourceURL ), beans::PropertyState_DIRECT_VALUE)); ucbhelper::cancelCommandExecution( ucb::IOErrorCode_CANT_WRITE, uno::Sequence< uno::Any >(&aProps, 1), xEnv, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Cannot copy data!" ) ), this ); // Unreachable } ///////////////////////////////////////////////////////////////////////// // Copy own and all children's Additional Core Properties. ///////////////////////////////////////////////////////////////////////// rtl::OUString aTargetUri = m_xIdentifier->getContentIdentifier(); if ( ( aTargetUri.lastIndexOf( '/' ) + 1 ) != aTargetUri.getLength() ) aTargetUri += rtl::OUString::createFromAscii( "/" ); if ( rInfo.NewTitle.getLength() > 0 ) aTargetUri += ::ucb_impl::urihelper::encodeSegment( rInfo.NewTitle ); else aTargetUri += aSourceUri.getName(); if ( !copyAdditionalPropertySet( aSourceUri.getUri(), aTargetUri, sal_True ) ) { uno::Any aProps = uno::makeAny( beans::PropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Uri")), -1, uno::makeAny( rInfo.SourceURL ), beans::PropertyState_DIRECT_VALUE)); ucbhelper::cancelCommandExecution( ucb::IOErrorCode_CANT_WRITE, uno::Sequence< uno::Any >(&aProps, 1), xEnv, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Cannot copy additional properties!" ) ), this ); // Unreachable } ///////////////////////////////////////////////////////////////////////// // Propagate new content. ///////////////////////////////////////////////////////////////////////// rtl::Reference< Content > xTarget; try { uno::Reference< ucb::XContentIdentifier > xTargetId = new ::ucbhelper::ContentIdentifier( m_xSMgr, aTargetUri ); // Note: The static cast is okay here, because its sure that // m_xProvider is always the WebDAVContentProvider. xTarget = static_cast< Content * >( m_pProvider->queryContent( xTargetId ).get() ); } catch ( ucb::IllegalIdentifierException const & ) { // queryContent } if ( !xTarget.is() ) { uno::Any aProps = uno::makeAny(beans::PropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Uri")), -1, uno::makeAny( aTargetUri ), beans::PropertyState_DIRECT_VALUE)); ucbhelper::cancelCommandExecution( ucb::IOErrorCode_CANT_READ, uno::Sequence< uno::Any >(&aProps, 1), xEnv, rtl::OUString::createFromAscii( "Cannot instanciate target object!" ), this ); // Unreachable } // Announce transferred content in its new folder. xTarget->inserted(); ///////////////////////////////////////////////////////////////////////// // Remove source, if requested ///////////////////////////////////////////////////////////////////////// if ( rInfo.MoveData ) { rtl::Reference< Content > xSource; try { uno::Reference< ucb::XContentIdentifier > xSourceId = new ::ucbhelper::ContentIdentifier( m_xSMgr, rInfo.SourceURL ); // Note: The static cast is okay here, because its sure // that m_xProvider is always the ContentProvider. xSource = static_cast< Content * >( m_xProvider->queryContent( xSourceId ).get() ); } catch ( ucb::IllegalIdentifierException const & ) { // queryContent } if ( !xSource.is() ) { uno::Any aProps = uno::makeAny(beans::PropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Uri")), -1, uno::makeAny( rInfo.SourceURL ), beans::PropertyState_DIRECT_VALUE)); ucbhelper::cancelCommandExecution( ucb::IOErrorCode_CANT_READ, uno::Sequence< uno::Any >(&aProps, 1), xEnv, rtl::OUString::createFromAscii( "Cannot instanciate target object!" ), this ); // Unreachable } // Propagate destruction (recursively). xSource->destroy( sal_True, xEnv ); // Remove all persistent data of source and its children. if ( !xSource->removeData() ) { uno::Any aProps = uno::makeAny( beans::PropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Uri")), -1, uno::makeAny( rInfo.SourceURL ), beans::PropertyState_DIRECT_VALUE)); ucbhelper::cancelCommandExecution( ucb::IOErrorCode_CANT_WRITE, uno::Sequence< uno::Any >(&aProps, 1), xEnv, rtl::OUString::createFromAscii( "Cannot remove persistent data of source object!" ), this ); // Unreachable } // Remove own and all children's Additional Core Properties. if ( !xSource->removeAdditionalPropertySet( sal_True ) ) { uno::Any aProps = uno::makeAny( beans::PropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Uri")), -1, uno::makeAny( rInfo.SourceURL ), beans::PropertyState_DIRECT_VALUE)); ucbhelper::cancelCommandExecution( ucb::IOErrorCode_CANT_WRITE, uno::Sequence< uno::Any >(&aProps, 1), xEnv, rtl::OUString::createFromAscii( "Cannot remove additional properties of source object!" ), this ); // Unreachable } } // rInfo.MoveData } //========================================================================= //static bool Content::hasData( ContentProvider* pProvider, const Uri & rUri ) { if ( rUri.isRoot() ) { return true; // root has no storage } else if ( rUri.isDocument() ) { uno::Reference< embed::XStorage > xStorage = pProvider->queryStorage( rUri.getUri(), READ ); return xStorage.is(); } else { // folder or stream // Ask parent storage. In case that rUri describes a stream, // ContentProvider::queryStorage( rUri ) would return null. uno::Reference< embed::XStorage > xStorage = pProvider->queryStorage( rUri.getParentUri(), READ ); if ( !xStorage.is() ) return false; uno::Reference< container::XNameAccess > xParentNA( xStorage, uno::UNO_QUERY ); OSL_ENSURE( xParentNA.is(), "Got no css.container.XNameAccess!" ); return xParentNA->hasByName( rUri.getDecodedName() ); } } //========================================================================= //static bool Content::loadData( ContentProvider* pProvider, const Uri & rUri, ContentProperties& rProps ) { if ( rUri.isRoot() ) // root has no storage, but can always be created { rProps = ContentProperties( ROOT, pProvider->queryStorageTitle( rUri.getUri() ) ); } else if ( rUri.isDocument() ) // document must have storage { uno::Reference< embed::XStorage > xStorage = pProvider->queryStorage( rUri.getUri(), READ ); if ( !xStorage.is() ) return false; rProps = ContentProperties( DOCUMENT, pProvider->queryStorageTitle( rUri.getUri() ) ); } else // stream or folder; stream has no storage; folder has storage { uno::Reference< embed::XStorage > xStorage = pProvider->queryStorage( rUri.getParentUri(), READ ); if ( !xStorage.is() ) return false; // Check whether exists at all, is stream or folder try { // return: true -> folder // return: false -> stream // NoSuchElementException -> neither folder nor stream bool bIsFolder = xStorage->isStorageElement( rUri.getDecodedName() ); rProps = ContentProperties( bIsFolder ? FOLDER : STREAM, pProvider->queryStorageTitle( rUri.getUri() ) ); } catch ( container::NoSuchElementException const & ) { // there is no element with such name //OSL_ENSURE( false, "Caught NoSuchElementException!" ); return false; } catch ( lang::IllegalArgumentException const & ) { // an illegal argument is provided OSL_ENSURE( false, "Caught IllegalArgumentException!" ); return false; } catch ( embed::InvalidStorageException const & ) { // this storage is in invalid state for any reason OSL_ENSURE( false, "Caught InvalidStorageException!" ); return false; } } return true; } //========================================================================= bool Content::storeData( const uno::Reference< io::XInputStream >& xData, const uno::Reference< ucb::XCommandEnvironment >& xEnv ) throw ( ucb::CommandFailedException, task::DocumentPasswordRequest ) { osl::Guard< osl::Mutex > aGuard( m_aMutex ); ContentType eType = m_aProps.getType(); if ( ( eType == ROOT ) || ( eType == DOCUMENT ) ) { OSL_ENSURE( false, "storeData not supported by root and documents!" ); return false; } Uri aUri( m_xIdentifier->getContentIdentifier() ); if ( eType == FOLDER ) { uno::Reference< embed::XStorage > xStorage = m_pProvider->queryStorage( aUri.getUri(), READ_WRITE_CREATE ); if ( !xStorage.is() ) return false; uno::Reference< beans::XPropertySet > xPropSet( xStorage, uno::UNO_QUERY ); OSL_ENSURE( xPropSet.is(), "Content::storeData - Got no XPropertySet interface!" ); if ( !xPropSet.is() ) return false; try { // According to MBA, if no mediatype is set, folder and all // its contents will be lost on save of the document!!! xPropSet->setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ), uno::makeAny( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( // @@@ better mediatype "application/binary" ) ) ) ); } catch ( beans::UnknownPropertyException const & ) { OSL_ENSURE( false, "Property MediaType not supported!" ); return false; } catch ( beans::PropertyVetoException const & ) { OSL_ENSURE( false, "Caught PropertyVetoException!" ); return false; } catch ( lang::IllegalArgumentException const & ) { OSL_ENSURE( false, "Caught IllegalArgumentException!" ); return false; } catch ( lang::WrappedTargetException const & ) { OSL_ENSURE( false, "Caught WrappedTargetException!" ); return false; } if ( !commitStorage( xStorage ) ) return false; } else if ( eType == STREAM ) { // stream // Important: Parent storage and output stream must be kept alive until // changes have been committed! uno::Reference< embed::XStorage > xStorage = m_pProvider->queryStorage( aUri.getParentUri(), READ_WRITE_CREATE ); uno::Reference< io::XOutputStream > xOut; if ( !xStorage.is() ) return false; if ( xData.is() ) { // May throw CommandFailedException, DocumentPasswordRequest! xOut = getTruncatedOutputStream( xEnv ); OSL_ENSURE( xOut.is(), "No target data stream!" ); try { uno::Sequence< sal_Int8 > aBuffer; sal_Int32 nRead = xData->readSomeBytes( aBuffer, 65536 ); while ( nRead > 0 ) { aBuffer.realloc( nRead ); xOut->writeBytes( aBuffer ); aBuffer.realloc( 0 ); nRead = xData->readSomeBytes( aBuffer, 65536 ); } closeOutputStream( xOut ); } catch ( io::NotConnectedException const & ) { // readSomeBytes, writeBytes OSL_ENSURE( false, "Caught NotConnectedException!" ); closeOutputStream( xOut ); return false; } catch ( io::BufferSizeExceededException const & ) { // readSomeBytes, writeBytes OSL_ENSURE( false, "Caught BufferSizeExceededException!" ); closeOutputStream( xOut ); return false; } catch ( io::IOException const & ) { // readSomeBytes, writeBytes OSL_ENSURE( false, "Caught IOException!" ); closeOutputStream( xOut ); return false; } catch ( ... ) { closeOutputStream( xOut ); throw; } } // Commit changes. if ( !commitStorage( xStorage ) ) return false; } else { OSL_ENSURE( false, "Unknown content type!" ); return false; } return true; } //========================================================================= bool Content::renameData( const uno::Reference< ucb::XContentIdentifier >& xOldId, const uno::Reference< ucb::XContentIdentifier >& xNewId ) { osl::Guard< osl::Mutex > aGuard( m_aMutex ); ContentType eType = m_aProps.getType(); if ( ( eType == ROOT ) || ( eType == DOCUMENT ) ) { OSL_ENSURE( false, "renameData not supported by root and documents!" ); return false; } Uri aOldUri( xOldId->getContentIdentifier() ); uno::Reference< embed::XStorage > xStorage = m_pProvider->queryStorage( aOldUri.getParentUri(), READ_WRITE_NOCREATE ); if ( !xStorage.is() ) return false; try { Uri aNewUri( xNewId->getContentIdentifier() ); xStorage->renameElement( aOldUri.getDecodedName(), aNewUri.getDecodedName() ); } catch ( embed::InvalidStorageException const & ) { // this storage is in invalid state for eny reason OSL_ENSURE( false, "Caught InvalidStorageException!" ); return false; } catch ( lang::IllegalArgumentException const & ) { // an illegal argument is provided OSL_ENSURE( false, "Caught IllegalArgumentException!" ); return false; } catch ( container::NoSuchElementException const & ) { // there is no element with old name in this storage OSL_ENSURE( false, "Caught NoSuchElementException!" ); return false; } catch ( container::ElementExistException const & ) { // an element with new name already exists in this storage OSL_ENSURE( false, "Caught ElementExistException!" ); return false; } catch ( io::IOException const & ) { // in case of io errors during renaming OSL_ENSURE( false, "Caught IOException!" ); return false; } catch ( embed::StorageWrappedTargetException const & ) { // wraps other exceptions OSL_ENSURE( false, "Caught StorageWrappedTargetException!" ); return false; } return commitStorage( xStorage ); } //========================================================================= bool Content::removeData() { osl::Guard< osl::Mutex > aGuard( m_aMutex ); ContentType eType = m_aProps.getType(); if ( ( eType == ROOT ) || ( eType == DOCUMENT ) ) { OSL_ENSURE( false, "removeData not supported by root and documents!" ); return false; } Uri aUri( m_xIdentifier->getContentIdentifier() ); uno::Reference< embed::XStorage > xStorage = m_pProvider->queryStorage( aUri.getParentUri(), READ_WRITE_NOCREATE ); if ( !xStorage.is() ) return false; try { xStorage->removeElement( aUri.getDecodedName() ); } catch ( embed::InvalidStorageException const & ) { // this storage is in invalid state for eny reason OSL_ENSURE( false, "Caught InvalidStorageException!" ); return false; } catch ( lang::IllegalArgumentException const & ) { // an illegal argument is provided OSL_ENSURE( false, "Caught IllegalArgumentException!" ); return false; } catch ( container::NoSuchElementException const & ) { // there is no element with this name in this storage OSL_ENSURE( false, "Caught NoSuchElementException!" ); return false; } catch ( io::IOException const & ) { // in case of io errors during renaming OSL_ENSURE( false, "Caught IOException!" ); return false; } catch ( embed::StorageWrappedTargetException const & ) { // wraps other exceptions OSL_ENSURE( false, "Caught StorageWrappedTargetException!" ); return false; } return commitStorage( xStorage ); } //========================================================================= bool Content::copyData( const Uri & rSourceUri, const rtl::OUString & rNewName ) { osl::Guard< osl::Mutex > aGuard( m_aMutex ); ContentType eType = m_aProps.getType(); if ( ( eType == ROOT ) || ( eType == STREAM ) ) { OSL_ENSURE( false, "copyData not supported by root and streams!" ); return false; } Uri aDestUri( m_xIdentifier->getContentIdentifier() ); uno::Reference< embed::XStorage > xDestStorage = m_pProvider->queryStorage( aDestUri.getUri(), READ_WRITE_NOCREATE ); if ( !xDestStorage.is() ) return false; uno::Reference< embed::XStorage > xSourceStorage = m_pProvider->queryStorage( rSourceUri.getParentUri(), READ ); if ( !xSourceStorage.is() ) return false; try { xSourceStorage->copyElementTo( rSourceUri.getDecodedName(), xDestStorage, rNewName ); } catch ( embed::InvalidStorageException const & ) { // this storage is in invalid state for eny reason OSL_ENSURE( false, "Caught InvalidStorageException!" ); return false; } catch ( lang::IllegalArgumentException const & ) { // an illegal argument is provided OSL_ENSURE( false, "Caught IllegalArgumentException!" ); return false; } catch ( container::NoSuchElementException const & ) { // there is no element with this name in this storage OSL_ENSURE( false, "Caught NoSuchElementException!" ); return false; } catch ( container::ElementExistException const & ) { // there is no element with this name in this storage OSL_ENSURE( false, "Caught ElementExistException!" ); return false; } catch ( io::IOException const & ) { // in case of io errors during renaming OSL_ENSURE( false, "Caught IOException!" ); return false; } catch ( embed::StorageWrappedTargetException const & ) { // wraps other exceptions OSL_ENSURE( false, "Caught StorageWrappedTargetException!" ); return false; } return commitStorage( xDestStorage ); } //========================================================================= // static bool Content::commitStorage( const uno::Reference< embed::XStorage > & xStorage ) { // Commit changes uno::Reference< embed::XTransactedObject > xTO( xStorage, uno::UNO_QUERY ); OSL_ENSURE( xTO.is(), "Required interface css.embed.XTransactedObject missing!" ); try { xTO->commit(); } catch ( io::IOException const & ) { OSL_ENSURE( false, "Caught IOException!" ); return false; } catch ( lang::WrappedTargetException const & ) { OSL_ENSURE( false, "Caught WrappedTargetException!" ); return false; } return true; } //========================================================================= // static bool Content::closeOutputStream( const uno::Reference< io::XOutputStream > & xOut ) { if ( xOut.is() ) { try { xOut->closeOutput(); return true; } catch ( io::NotConnectedException const & ) { OSL_ENSURE( false, "Caught NotConnectedException!" ); } catch ( io::BufferSizeExceededException const & ) { OSL_ENSURE( false, "Caught BufferSizeExceededException!" ); } catch ( io::IOException const & ) { OSL_ENSURE( false, "Caught IOException!" ); } } return false; } //========================================================================= static rtl::OUString obtainPassword( const rtl::OUString & rName, task::PasswordRequestMode eMode, const uno::Reference< ucb::XCommandEnvironment > & xEnv ) throw ( ucb::CommandFailedException, task::DocumentPasswordRequest ) { rtl::Reference< DocumentPasswordRequest > xRequest = new DocumentPasswordRequest( eMode, rName ); if ( xEnv.is() ) { uno::Reference< task::XInteractionHandler > xIH = xEnv->getInteractionHandler(); if ( xIH.is() ) { xIH->handle( xRequest.get() ); rtl::Reference< ucbhelper::InteractionContinuation > xSelection = xRequest->getSelection(); if ( xSelection.is() ) { // Handler handled the request. uno::Reference< task::XInteractionAbort > xAbort( xSelection.get(), uno::UNO_QUERY ); if ( xAbort.is() ) { throw ucb::CommandFailedException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Abort requested by Interaction Handler." ) ), uno::Reference< uno::XInterface >(), xRequest->getRequest() ); } uno::Reference< task::XInteractionPassword > xPassword( xSelection.get(), uno::UNO_QUERY ); if ( xPassword.is() ) { return xPassword->getPassword(); } // Unknown selection. Should never happen. throw ucb::CommandFailedException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Interaction Handler selected unknown continuation!" ) ), uno::Reference< uno::XInterface >(), xRequest->getRequest() ); } } } // No IH or IH did not handle exception. task::DocumentPasswordRequest aRequest; xRequest->getRequest() >>= aRequest; throw aRequest; } //========================================================================= uno::Reference< io::XInputStream > Content::getInputStream( const uno::Reference< ucb::XCommandEnvironment > & xEnv ) throw ( ucb::CommandFailedException, task::DocumentPasswordRequest ) { rtl::OUString aUri; rtl::OUString aPassword; bool bPasswordRequested = false; { osl::Guard< osl::Mutex > aGuard( m_aMutex ); OSL_ENSURE( m_aProps.getType() == STREAM, "Content::getInputStream - content is no stream!" ); aUri = Uri( m_xIdentifier->getContentIdentifier() ).getUri(); } for ( ;; ) { try { osl::Guard< osl::Mutex > aGuard( m_aMutex ); return uno::Reference< io::XInputStream >( m_pProvider->queryInputStream( aUri, aPassword ) ); } catch ( packages::WrongPasswordException const & ) { // Obtain (new) password. aPassword = obtainPassword( aUri, /* @@@ find better title */ bPasswordRequested ? task::PasswordRequestMode_PASSWORD_REENTER : task::PasswordRequestMode_PASSWORD_ENTER, xEnv ); bPasswordRequested = true; } } } //========================================================================= static uno::Reference< io::XOutputStream > lcl_getTruncatedOutputStream( const rtl::OUString & rUri, ContentProvider * pProvider, const uno::Reference< ucb::XCommandEnvironment > & xEnv ) throw ( ucb::CommandFailedException, task::DocumentPasswordRequest ) { rtl::OUString aPassword; bool bPasswordRequested = false; for ( ;; ) { try { return uno::Reference< io::XOutputStream >( pProvider->queryOutputStream( rUri, aPassword, true /* truncate */ ) ); } catch ( packages::WrongPasswordException const & ) { // Obtain (new) password. aPassword = obtainPassword( rUri, /* @@@ find better title */ bPasswordRequested ? task::PasswordRequestMode_PASSWORD_REENTER : task::PasswordRequestMode_PASSWORD_ENTER, xEnv ); bPasswordRequested = true; } } } //========================================================================= uno::Reference< io::XOutputStream > Content::getTruncatedOutputStream( const uno::Reference< ucb::XCommandEnvironment > & xEnv ) throw ( ucb::CommandFailedException, task::DocumentPasswordRequest ) { OSL_ENSURE( m_aProps.getType() == STREAM, "Content::getTruncatedOutputStream - content is no stream!" ); return lcl_getTruncatedOutputStream( Uri( m_xIdentifier->getContentIdentifier() ).getUri(), m_pProvider, xEnv ); } //========================================================================= uno::Reference< io::XStream > Content::getStream( const uno::Reference< ucb::XCommandEnvironment > & xEnv ) throw ( ucb::CommandFailedException, task::DocumentPasswordRequest ) { osl::Guard< osl::Mutex > aGuard( m_aMutex ); OSL_ENSURE( m_aProps.getType() == STREAM, "Content::getStream - content is no stream!" ); rtl::OUString aUri( Uri( m_xIdentifier->getContentIdentifier() ).getUri() ); rtl::OUString aPassword; bool bPasswordRequested = false; for ( ;; ) { try { return uno::Reference< io::XStream >( m_pProvider->queryStream( aUri, aPassword, false /* no truncate */ ) ); } catch ( packages::WrongPasswordException const & ) { // Obtain (new) password. aPassword = obtainPassword( aUri, /* @@@ find better title */ bPasswordRequested ? task::PasswordRequestMode_PASSWORD_REENTER : task::PasswordRequestMode_PASSWORD_ENTER, xEnv ); bPasswordRequested = true; } } } //========================================================================= //========================================================================= // // ContentProperties Implementation. // //========================================================================= //========================================================================= uno::Sequence< ucb::ContentInfo > ContentProperties::getCreatableContentsInfo() const { if ( isContentCreator() ) { uno::Sequence< beans::Property > aProps( 1 ); aProps.getArray()[ 0 ] = beans::Property( rtl::OUString::createFromAscii( "Title" ), -1, getCppuType( static_cast< const rtl::OUString * >( 0 ) ), beans::PropertyAttribute::BOUND ); #ifdef NO_STREAM_CREATION_WITHIN_DOCUMENT_ROOT if ( getType() == DOCUMENT ) { // streams cannot be created as direct children of document root uno::Sequence< ucb::ContentInfo > aSeq( 1 ); // Folder. aSeq.getArray()[ 0 ].Type = rtl::OUString::createFromAscii( TDOC_FOLDER_CONTENT_TYPE ); aSeq.getArray()[ 0 ].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER; aSeq.getArray()[ 0 ].Properties = aProps; return aSeq; } else { #endif uno::Sequence< ucb::ContentInfo > aSeq( 2 ); // Folder. aSeq.getArray()[ 0 ].Type = rtl::OUString::createFromAscii( TDOC_FOLDER_CONTENT_TYPE ); aSeq.getArray()[ 0 ].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER; aSeq.getArray()[ 0 ].Properties = aProps; // Stream. aSeq.getArray()[ 1 ].Type = rtl::OUString::createFromAscii( TDOC_STREAM_CONTENT_TYPE ); aSeq.getArray()[ 1 ].Attributes = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM | ucb::ContentInfoAttribute::KIND_DOCUMENT; aSeq.getArray()[ 1 ].Properties = aProps; return aSeq; #ifdef NO_STREAM_CREATION_WITHIN_DOCUMENT_ROOT } #endif } else { OSL_ENSURE( sal_False, "getCreatableContentsInfo called on non-contentcreator " "object!" ); return uno::Sequence< ucb::ContentInfo >( 0 ); } } //========================================================================= bool ContentProperties::isContentCreator() const { return ( getType() == FOLDER ) || ( getType() == DOCUMENT ); }