diff options
author | Cédric Bosdonnat <cedric.bosdonnat@free.fr> | 2012-05-29 15:18:29 +0200 |
---|---|---|
committer | Cédric Bosdonnat <cedric.bosdonnat@free.fr> | 2012-06-04 13:28:12 +0200 |
commit | 966d20e35d5a2be2fce6c204af5c156c3ead7063 (patch) | |
tree | e23f080a8831d398508d7b1731c315310021aed8 /ucb | |
parent | 12d193df238adaf67608327b36fea91003138539 (diff) |
CMIS ucp: write documents back to CMIS server
This change needs a git repo build of libcmis.
Change-Id: I I740d18dbf3c36d9387b867e750fcbe8e114e5362
Diffstat (limited to 'ucb')
-rw-r--r-- | ucb/source/ucp/cmis/cmis_content.cxx | 516 | ||||
-rw-r--r-- | ucb/source/ucp/cmis/cmis_content.hxx | 16 | ||||
-rw-r--r-- | ucb/source/ucp/cmis/cmis_provider.cxx | 31 | ||||
-rw-r--r-- | ucb/source/ucp/cmis/cmis_provider.hxx | 7 | ||||
-rw-r--r-- | ucb/source/ucp/cmis/cmis_url.cxx | 47 | ||||
-rw-r--r-- | ucb/source/ucp/cmis/cmis_url.hxx | 18 |
6 files changed, 497 insertions, 138 deletions
diff --git a/ucb/source/ucp/cmis/cmis_content.cxx b/ucb/source/ucp/cmis/cmis_content.cxx index 8c12f93157b8..ead9f2da4ab0 100644 --- a/ucb/source/ucp/cmis/cmis_content.cxx +++ b/ucb/source/ucp/cmis/cmis_content.cxx @@ -32,10 +32,19 @@ #include <com/sun/star/beans/PropertyValue.hpp> #include <com/sun/star/beans/XPropertySetInfo.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/task/InteractionClassification.hpp> +#include <com/sun/star/ucb/ContentInfo.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/NameClash.hpp> +#include <com/sun/star/ucb/NameClashException.hpp> #include <com/sun/star/ucb/OpenMode.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/XDynamicResultSet.hpp> @@ -44,17 +53,80 @@ #include <ucbhelper/cancelcommandexecution.hxx> #include <ucbhelper/contentidentifier.hxx> -#include <ucbhelper/fd_inputstream.hxx> +#include <ucbhelper/std_inputstream.hxx> +#include <ucbhelper/std_outputstream.hxx> #include <ucbhelper/propertyvalueset.hxx> +#include <ucbhelper/simpleauthenticationrequest.hxx> #include "cmis_content.hxx" #include "cmis_provider.hxx" -#include "cmis_url.hxx" +#define OUSTR_TO_STDSTR(s) string( rtl::OUStringToOString( s, RTL_TEXTENCODING_UTF8 ).getStr() ) using namespace com::sun::star; using namespace std; +namespace +{ + class AuthProvider : public libcmis::AuthProvider + { + const com::sun::star::uno::Reference< com::sun::star::ucb::XCommandEnvironment>& m_xEnv; + rtl::OUString m_sUrl; + rtl::OUString m_sBindingUrl; + + public: + AuthProvider ( const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment>& xEnv, + rtl::OUString sUrl, + rtl::OUString sBindingUrl ): + m_xEnv( xEnv ), m_sUrl( sUrl ), m_sBindingUrl( sBindingUrl ) { } + + bool authenticationQuery( string& username, string& password ); + }; + + bool AuthProvider::authenticationQuery( string& username, string& password ) + { + if ( m_xEnv.is() ) + { + uno::Reference< task::XInteractionHandler > xIH + = m_xEnv->getInteractionHandler(); + + if ( xIH.is() ) + { + rtl::Reference< ucbhelper::SimpleAuthenticationRequest > xRequest + = new ucbhelper::SimpleAuthenticationRequest( + m_sUrl, m_sBindingUrl, ::rtl::OUString(), + rtl::OUString::createFromAscii( username.c_str( ) ), + rtl::OUString::createFromAscii( password.c_str( ) ), + ::rtl::OUString(), true, false ); + 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() ) + { + const rtl::Reference< + ucbhelper::InteractionSupplyAuthentication > & xSupp + = xRequest->getAuthenticationSupplier(); + + username = OUSTR_TO_STDSTR( xSupp->getUserName() ); + password = OUSTR_TO_STDSTR( xSupp->getPassword() ); + + return true; + } + } + } + } + return false; + } +} + namespace cmis { Content::Content( const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, @@ -62,43 +134,85 @@ namespace cmis throw ( ucb::ContentCreationException ) : ContentImplHelper( rxSMgr, pProvider, Identifier ), m_pProvider( pProvider ), - m_pSession( NULL ) + m_pSession( NULL ), + m_bTransient( false ) { -#if OSL_DEBUG_LEVEL > 1 - fprintf(stderr, "New Content ('%s')\n", rtl::OUStringToOString(m_xIdentifier->getContentIdentifier(), RTL_TEXTENCODING_UTF8).getStr()); -#endif // Split the URL into bits - cmis::URL url( m_xIdentifier->getContentIdentifier() ); + m_sURL = m_xIdentifier->getContentIdentifier( ); + cmis::URL url( m_sURL ); - // Initiate a CMIS session - m_pSession = libcmis::SessionFactory::createSession( url.getSessionParams( ) ); + // Look for a cached session + m_pSession = pProvider->getSession( url.getBindingUrl( ) ); + if ( NULL == m_pSession ) + { + // Initiate a CMIS session and register it as we found nothing + m_pSession = libcmis::SessionFactory::createSession( url.getSessionParams( ) ); + pProvider->registerSession( url.getBindingUrl( ), m_pSession ); + } - // Get the content Object - m_pObject = m_pSession->getObject( url.getObjectId() ); + m_sObjectId = url.getObjectId( ); + m_sBindingUrl = url.getBindingUrl( ); } Content::Content( const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, ContentProvider *pProvider, const uno::Reference< ucb::XContentIdentifier >& Identifier, - sal_Bool /*bIsFolder*/) + sal_Bool bIsFolder ) throw ( ucb::ContentCreationException ) : ContentImplHelper( rxSMgr, pProvider, Identifier ), m_pProvider( pProvider ), - m_pSession( NULL ) + m_pSession( NULL ), + m_bTransient( true ) { -#if OSL_DEBUG_LEVEL > 1 - fprintf(stderr, "TODO - Create Content ('%s')\n", rtl::OUStringToOString(m_xIdentifier->getContentIdentifier(), RTL_TEXTENCODING_UTF8).getStr()); -#endif - // TODO Implement me + // Split the URL into bits + m_sURL = m_xIdentifier->getContentIdentifier( ); + cmis::URL url( m_sURL ); + + // Look for a cached session + m_pSession = pProvider->getSession( url.getBindingUrl( ) ); + if ( NULL == m_pSession ) + { + // Initiate a CMIS session and register it as we found nothing + m_pSession = libcmis::SessionFactory::createSession( url.getSessionParams( ) ); + pProvider->registerSession( url.getBindingUrl( ), m_pSession ); + } + + m_sObjectId = url.getObjectId( ); + m_sBindingUrl = url.getBindingUrl( ); + + // Get the object type + string typeId = bIsFolder ? "cmis:folder" : "cmis:document"; + m_pObjectType = m_pSession->getType( typeId ); } Content::~Content() { - delete m_pSession; } - bool Content::isFolder(const uno::Reference< ucb::XCommandEnvironment >& /*xEnv*/) + libcmis::ObjectPtr Content::getObject( ) { - return m_pObject->getBaseType( ) == "cmis::folder"; + try + { + if ( !m_pObject.get() ) + m_pObject = m_pSession->getObject( OUSTR_TO_STDSTR( m_sObjectId ) ); + } + catch ( const libcmis::Exception& e ) + { + SAL_INFO( "cmisucp", "Unexpected exception: " << e.what() ); + } + + return m_pObject; + } + + void Content::resetAuthProvider( const uno::Reference< ucb::XCommandEnvironment >& xEnv ) + { + libcmis::AuthProviderPtr authProvider( new AuthProvider( xEnv, m_sURL, m_sBindingUrl ) ); + m_pSession->setAuthenticationProvider( authProvider ); + } + + bool Content::isFolder(const uno::Reference< ucb::XCommandEnvironment >& xEnv ) + { + resetAuthProvider( xEnv ); + return getObject( )->getBaseType( ) == "cmis:folder"; } uno::Any Content::getBadArgExcept() @@ -110,11 +224,10 @@ namespace cmis uno::Reference< sdbc::XRow > Content::getPropertyValues( const uno::Sequence< beans::Property >& rProperties, - const uno::Reference< ucb::XCommandEnvironment >& /*xEnv*/ ) + const uno::Reference< ucb::XCommandEnvironment >& xEnv ) { -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "TODO - cmis::Content::getPropertyValues()\n" ); -#endif + resetAuthProvider( xEnv ); + rtl::Reference< ::ucbhelper::PropertyValueSet > xRow = new ::ucbhelper::PropertyValueSet( m_xSMgr ); sal_Int32 nProps; @@ -126,59 +239,84 @@ namespace cmis for( sal_Int32 n = 0; n < nProps; ++n ) { const beans::Property& rProp = pProps[ n ]; -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "Property: %s\n", rtl::OUStringToOString( rProp.Name, RTL_TEXTENCODING_UTF8 ).getStr() ); -#endif if ( rProp.Name == "IsDocument" ) { - if ( m_pObject->getBaseType( ) == "cmis:document" ) + if ( getObject()->getBaseType( ) == "cmis:document" ) xRow->appendBoolean( rProp, true ); else xRow->appendVoid( rProp ); } else if ( rProp.Name == "IsFolder" ) { - if( m_pObject->getBaseType( ) == "cmis:folder" ) + if( getObject()->getBaseType( ) == "cmis:folder" ) xRow->appendBoolean( rProp, true ); else xRow->appendVoid( rProp ); } + else if ( rProp.Name == "Title" ) + { + string name = getObject()->getName(); + xRow->appendString( rProp, rtl::OUString::createFromAscii( name.c_str() ) ); + } else if ( rProp.Name == "TitleOnServer" ) { - // TODO Set the path instead of the name - xRow->appendString( rProp, rtl::OUString::createFromAscii( m_pObject->getName().c_str() ) ); + string path; + libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject().get( ) ); + if ( NULL != document ) + { + vector< boost::shared_ptr< libcmis::Folder > > parents = document->getParents( ); + if ( parents.size() > 0 ) + path = parents.front( )->getPath( ); + + if ( path[ path.length() - 1 ] != '/' ) + path += "/"; + path += getObject()->getName( ); + } + else + { + libcmis::Folder* folder = dynamic_cast< libcmis::Folder* >( getObject().get( ) ); + if ( NULL != folder ) + path = folder->getPath( ); + } + + xRow->appendString( rProp, rtl::OUString::createFromAscii( path.c_str() ) ); } else if ( rProp.Name == "IsReadOnly" ) { - // TODO Fix this value - xRow->appendBoolean( rProp, sal_True ); + boost::shared_ptr< libcmis::AllowableActions > allowableActions = getObject()->getAllowableActions( ); + sal_Bool bReadOnly = sal_False; + if ( allowableActions->isAllowed( libcmis::ObjectAction::SetContentStream ) ) + bReadOnly = sal_True; + + xRow->appendBoolean( rProp, bReadOnly ); } else if ( rProp.Name == "DateCreated" ) { // TODO Fix this value + SAL_INFO( "cmisucp", "TODO - Fix property value " << rProp.Name ); xRow->appendVoid( rProp ); } else if ( rProp.Name == "DateModified" ) { // TODO Fix this value + SAL_INFO( "cmisucp", "TODO - Fix property value " << rProp.Name ); xRow->appendVoid( rProp ); } else if ( rProp.Name == "Size" ) { - libcmis::Document* document = dynamic_cast< libcmis::Document* >( m_pObject.get( ) ); + libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject().get( ) ); if ( NULL != document ) xRow->appendLong( rProp, document->getContentLength() ); else xRow->appendVoid( rProp ); } -#if OSL_DEBUG_LEVEL > 1 - else + else if ( rProp.Name == "CreatableContentsInfo" ) { - fprintf( stderr, "Looking for unsupported property %s\n", - rtl::OUStringToOString( rProp.Name, RTL_TEXTENCODING_UTF8 ).getStr( ) ); + xRow->appendObject( rProp, uno::makeAny( queryCreatableContentsInfo( xEnv ) ) ); } -#endif + else + SAL_INFO( "cmisucp", "Looking for unsupported property " << rProp.Name ); } return uno::Reference< sdbc::XRow >( xRow.get() ); @@ -186,9 +324,7 @@ namespace cmis void Content::queryChildren( ContentRefList& /*rChildren*/ ) { -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "TODO - cmis::Content::queryChildren()\n" ); -#endif + SAL_INFO( "cmisucp", "TODO - Content::queryChildren()" ); // TODO Implement me } @@ -210,10 +346,8 @@ namespace cmis if ( bOpenFolder && bIsFolder ) { -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "TODO - cmis::Content::open() - Folder case\n" ); -#endif - // TODO Implement the folder case + SAL_INFO( "cmisucp", "TODO - Content::open() - Folder case" ); + // TODO Handle the folder case } else if ( rOpenCommand.Sink.is() ) { @@ -234,10 +368,7 @@ namespace cmis // Note: rOpenCommand.Sink may contain an XStream // implementation. Support for this type of // sink is optional... -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "Failed to load data from '%s'\n", - rtl::OUStringToOString( m_xIdentifier->getContentIdentifier(), RTL_TEXTENCODING_UTF8 ).getStr() ); -#endif + SAL_INFO( "cmisucp", "Failed to copy data to sink" ); ucbhelper::cancelCommandExecution( uno::makeAny (ucb::UnsupportedDataSinkException @@ -247,36 +378,115 @@ namespace cmis } } else - fprintf( stderr, "Open falling through ..." ); + SAL_INFO( "cmisucp", "Open falling through ..." ); return aRet; } - void Content::transfer( const ucb::TransferInfo& /*rTransferInfo*/, - const uno::Reference< ucb::XCommandEnvironment > & /*xEnv*/ ) + void Content::transfer( const ucb::TransferInfo& rTransferInfo, + const uno::Reference< ucb::XCommandEnvironment > & xEnv ) throw( uno::Exception ) { -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "TODO - cmis::Content::transfer()\n" ); -#endif - // TODO Implement me + // If the source isn't on the same CMIS repository, then simply copy + INetURLObject aSourceUrl( rTransferInfo.SourceURL ); + if ( aSourceUrl.GetProtocol() != INET_PROT_CMIS_ATOM ) + { + rtl::OUString sSrcBindingUrl = URL( rTransferInfo.SourceURL ).getBindingUrl( ); + if ( sSrcBindingUrl != m_sBindingUrl ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( + ucb::InteractiveBadTransferURLException( + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "Unsupported URL scheme!" )), + static_cast< cppu::OWeakObject * >( this ) ) ), + xEnv ); + } + } + + SAL_INFO( "cmisucp", "TODO - Content::transfer()" ); } - void Content::insert( const uno::Reference< io::XInputStream > & /*xInputStream*/, - sal_Bool /*bReplaceExisting*/, const uno::Reference< ucb::XCommandEnvironment >& /*xEnv*/ ) + void Content::insert( const uno::Reference< io::XInputStream > & xInputStream, + sal_Bool bReplaceExisting, const uno::Reference< ucb::XCommandEnvironment >& xEnv ) throw( uno::Exception ) { -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "TODO - cmis::Content::insert()\n" ); -#endif - // TODO Implement me + SAL_INFO( "cmisucp", "TODO - Content::insert()" ); + + if ( !xInputStream.is() ) + { + ucbhelper::cancelCommandExecution( uno::makeAny + ( ucb::MissingInputStreamException + ( rtl::OUString(), static_cast< cppu::OWeakObject * >( this ) ) ), + xEnv ); + } + + try + { + // For transient content, the URL is the one of the parent + if ( m_bTransient ) + { + // Try to get the object from the server if there is any + libcmis::Folder* pFolder = dynamic_cast< libcmis::Folder* >( getObject( ).get( ) ); + if ( pFolder != NULL ) + { + map< string, libcmis::PropertyPtr >::iterator it = m_pObjectProps.find( "cmis:name" ); + if ( it == m_pObjectProps.end( ) ) + { + ucbhelper::cancelCommandExecution( uno::makeAny + ( uno::RuntimeException( "Missing name property", + static_cast< cppu::OWeakObject * >( this ) ) ), + xEnv ); + } + string newName = it->second->getStrings( ).front( ); + string newPath = pFolder->getPath( ); + if ( newPath[ newPath.size( ) - 1 ] != '/' ) + newPath += "/"; + newPath += newName; + + libcmis::ObjectPtr object = m_pSession->getObjectByPath( newPath ); + + if ( NULL != object.get( ) ) + { + // Are the base type matching? + if ( object->getBaseType( ) != m_pObjectType->getBaseType( )->getId() ) + { + ucbhelper::cancelCommandExecution( uno::makeAny + ( uno::RuntimeException( "Can't change a folder into a document and vice-versa.", + static_cast< cppu::OWeakObject * >( this ) ) ), + xEnv ); + } + + // Update the existing object if it's a document + libcmis::Document* document = dynamic_cast< libcmis::Document* >( object.get( ) ); + if ( NULL != document ) + { + boost::shared_ptr< ostream > pOut( new ostringstream ( ios_base::binary | ios_base::in | ios_base::out ) ); + uno::Reference < io::XOutputStream > xOutput = new ucbhelper::StdOutputStream( pOut ); + copyData( xInputStream, xOutput ); + document->setContentStream( pOut, string( ), bReplaceExisting ); + } + } + else + { + // TODO We need to create a brand new object... either folder or document + } + } + } + else + { + // TODO Update the current object... but I'm not sure this case can happen with UCB + } + } + catch ( const libcmis::Exception& e ) + { + throw uno::Exception( rtl::OUString::createFromAscii( e.what( ) ), *this ); + } } - void Content::destroy( sal_Bool /*bDeletePhysical*/ ) throw( uno::Exception ) + void Content::destroy( sal_Bool /*bDeletePhysical*/ ) throw ( uno::Exception ) { -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "TODO - cmis::Content::destroy()\n" ); -#endif + SAL_INFO( "cmisucp", "TODO - Content::destroy()" ); // TODO Implement me } @@ -298,13 +508,57 @@ namespace cmis const uno::Sequence< beans::PropertyValue >& rValues, const uno::Reference< ucb::XCommandEnvironment >& ) { + // Get the already set properties if possible + if ( !m_bTransient && getObject( ).get( ) ) + m_pObjectProps = getObject()->getProperties( ); + sal_Int32 nCount = rValues.getLength(); uno::Sequence< uno::Any > aRet( nCount ); -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "TODO - cmis::Content::setPropertyValue()\n" ); -#endif - // TODO Implement me + const beans::PropertyValue* pValues = rValues.getConstArray(); + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + const beans::PropertyValue& rValue = pValues[ n ]; + if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) || + rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) || + rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) || + rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) || + rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Size" ) ) || + rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) ) + { + lang::IllegalAccessException e ( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Property is read-only!")), + static_cast< cppu::OWeakObject* >( this ) ); + aRet[ n ] <<= e; + } + else if ( rValue.Name == "Title" ) + { + rtl::OUString aNewTitle; + if (!( rValue.Value >>= aNewTitle )) + { + aRet[ n ] <<= beans::IllegalTypeException + ( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Property value has wrong type!")), + static_cast< cppu::OWeakObject * >( this ) ); + continue; + } + + if ( aNewTitle.getLength() <= 0 ) + { + aRet[ n ] <<= lang::IllegalArgumentException + ( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Empty title not allowed!")), + static_cast< cppu::OWeakObject * >( this ), -1 ); + continue; + + } + + setCmisProperty( "cmis:name", OUSTR_TO_STDSTR( aNewTitle ) ); + } + else + { + lang::IllegalAccessException e ( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Property is read-only!")), + static_cast< cppu::OWeakObject* >( this ) ); + aRet[ n ] <<= e; + } + } return aRet; } @@ -317,14 +571,18 @@ namespace cmis uno::Reference< io::XOutputStream > xOut = uno::Reference< io::XOutputStream >(xSink, uno::UNO_QUERY ); uno::Reference< io::XActiveDataSink > xDataSink = uno::Reference< io::XActiveDataSink >(xSink, uno::UNO_QUERY ); + uno::Reference< io::XActiveDataStreamer > xDataStreamer = uno::Reference< io::XActiveDataStreamer >( xSink, uno::UNO_QUERY ); - if ( !xOut.is() && !xDataSink.is() ) + if ( !xOut.is() && !xDataSink.is() && ( !xDataStreamer.is() || !xDataStreamer->getStream().is() ) ) return sal_False; - libcmis::Document* document = dynamic_cast< libcmis::Document* >( m_pObject.get() ); - FILE* fd = document->getContent( ); + if ( xDataStreamer.is() && !xOut.is() ) + xOut = xDataStreamer->getStream()->getOutputStream(); + + libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject().get() ); + boost::shared_ptr< istream > aIn = document->getContentStream( ); - uno::Reference< io::XInputStream > xIn = new ucbhelper::FdInputStream( fd ); + uno::Reference< io::XInputStream > xIn = new ucbhelper::StdInputStream( aIn ); if( !xIn.is( ) ) return sal_False; @@ -339,17 +597,17 @@ namespace cmis sal_Bool Content::exchangeIdentity( const uno::Reference< ucb::XContentIdentifier >& /*xNewId*/ ) { sal_Bool bRet = sal_False; -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "TODO - cmis::Content::exchangeIdentity()\n" ); -#endif + SAL_INFO( "cmisucp", "TODO - Content::exchangeIdentity()" ); // TODO Implement me return bRet; } uno::Sequence< beans::Property > Content::getProperties( - const uno::Reference< ucb::XCommandEnvironment > & /*xEnv*/ ) + const uno::Reference< ucb::XCommandEnvironment > & xEnv ) { + resetAuthProvider( xEnv ); + static const beans::Property aGenericProperties[] = { beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDocument" ) ), @@ -358,6 +616,9 @@ namespace cmis beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ), -1, getCppuBooleanType(), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), + beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ), + -1, getCppuType( static_cast< const rtl::OUString * >( 0 ) ), + beans::PropertyAttribute::BOUND ), beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TitleOnServer" ) ), -1, getCppuType( static_cast< const rtl::OUString * >( 0 ) ), beans::PropertyAttribute::BOUND ), @@ -373,6 +634,9 @@ namespace cmis beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Size" ) ), -1, getCppuType( static_cast< const sal_Int64 * >( 0 ) ), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), + beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CreatableContentsInfo" ) ), + -1, getCppuType( static_cast< const uno::Sequence< ucb::ContentInfo > * >( 0 ) ), + beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), }; const int nProps = SAL_N_ELEMENTS(aGenericProperties); @@ -382,6 +646,8 @@ namespace cmis uno::Sequence< ucb::CommandInfo > Content::getCommands( const uno::Reference< ucb::XCommandEnvironment > & xEnv ) { + resetAuthProvider( xEnv ); + static ucb::CommandInfo aCommandInfoTable[] = { // Required commands @@ -426,10 +692,31 @@ namespace cmis { rtl::OUString sRet; -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "TODO - cmis::Content::getParentURL()\n" ); -#endif - // TODO Implement me + SAL_INFO( "cmisucp", "Content::getParentURL()" ); + + string parentId; + + libcmis::ObjectPtr pObj = getObject( ); + libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject( ).get( ) ); + if ( NULL != document ) + { + vector< boost::shared_ptr< libcmis::Folder > > parents = document->getParents( ); + if ( parents.size( ) > 0 ) + parentId = parents.front( )->getId( ); + } + else + { + libcmis::Folder* folder = dynamic_cast< libcmis::Folder* >( getObject( ).get( ) ); + if ( NULL != folder ) + parentId = folder->getFolderParent( )->getId( ); + } + + if ( !parentId.empty() ) + { + URL aUrl( m_sURL ); + aUrl.setObjectId( rtl::OUString::createFromAscii( parentId.c_str( ) ) ); + sRet = aUrl.asString( ); + } return sRet; } @@ -478,6 +765,9 @@ namespace cmis const uno::Reference< ucb::XCommandEnvironment >& xEnv ) throw( uno::Exception, ucb::CommandAbortedException, uno::RuntimeException ) { + SAL_INFO( "cmisucp", "Content::execute( ) - " << aCommand.Name ); + resetAuthProvider( xEnv ); + uno::Any aRet; if ( aCommand.Name == "getPropertyValues" ) @@ -531,19 +821,11 @@ namespace cmis { sal_Bool bDeletePhysical = sal_False; aCommand.Argument >>= bDeletePhysical; - -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "TODO - cmis::Content::execute() - delete\n" ); -#endif - // TODO Actually delete it - destroy( bDeletePhysical ); } else { -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "cmis::Content::execute() - UNKNOWN COMMAND\n" ); -#endif + SAL_INFO( "cmisucp", "Unknown command to execute" ); ucbhelper::cancelCommandExecution ( uno::makeAny( ucb::UnsupportedCommandException @@ -557,9 +839,7 @@ namespace cmis void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ ) throw( uno::RuntimeException ) { -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "TODO - cmis::Content::abort()\n" ); -#endif + SAL_INFO( "cmisucp", "TODO - Content::abort()" ); // TODO Implement me } @@ -573,7 +853,6 @@ namespace cmis const ucb::ContentInfo& Info ) throw( uno::RuntimeException ) { bool create_document; - const char *name; if ( Info.Type == CMIS_FILE_TYPE ) create_document = true; @@ -581,33 +860,23 @@ namespace cmis create_document = false; else { -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "Failed to create new content '%s'", - rtl::OUStringToOString(Info.Type, RTL_TEXTENCODING_UTF8).getStr() ); -#endif + SAL_INFO( "cmisucp", "Unknown type of content to create" ); return uno::Reference< ucb::XContent >(); } -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "createNewContent (%d)", (int) create_document ); -#endif - - rtl::OUString aURL = m_xIdentifier->getContentIdentifier(); - - if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() ) - aURL += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")); - - name = create_document ? "[New_Content]" : "[New_Collection]"; - aURL += rtl::OUString::createFromAscii( name ); + rtl::OUString sParentURL = m_xIdentifier->getContentIdentifier(); + URL aParentURL( sParentURL ); - uno::Reference< ucb::XContentIdentifier > xId(new ::ucbhelper::ContentIdentifier(m_xSMgr, aURL)); + // Set the parent URL for the transient objects + uno::Reference< ucb::XContentIdentifier > xId(new ::ucbhelper::ContentIdentifier(m_xSMgr, sParentURL)); try { return new ::cmis::Content( m_xSMgr, m_pProvider, xId, !create_document ); - } catch ( ucb::ContentCreationException & ) + } + catch ( ucb::ContentCreationException & ) { - return uno::Reference< ucb::XContent >(); + return uno::Reference< ucb::XContent >(); } } @@ -652,6 +921,7 @@ namespace cmis const uno::Reference< ucb::XCommandEnvironment >& xEnv) throw( uno::RuntimeException ) { + resetAuthProvider( xEnv ); if ( isFolder( xEnv ) ) { uno::Sequence< ucb::ContentInfo > seq(2); @@ -682,6 +952,24 @@ namespace cmis return uno::Sequence< ucb::ContentInfo >(); } } + + void Content::setCmisProperty( std::string sName, std::string sValue ) + { + if ( m_pObjectType.get( ) ) + { + map< string, libcmis::PropertyTypePtr > propsTypes = m_pObjectType->getPropertiesTypes( ); + map< string, libcmis::PropertyTypePtr >::iterator typeIt = propsTypes.find( sName ); + + if ( typeIt != propsTypes.end( ) ) + { + libcmis::PropertyTypePtr propType = typeIt->second; + vector< string > values; + values.push_back( sValue ); + libcmis::PropertyPtr property( new libcmis::Property( propType, values ) ); + m_pObjectProps.insert( pair< string, libcmis::PropertyPtr >( sName, property ) ); + } + } + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/cmis/cmis_content.hxx b/ucb/source/ucp/cmis/cmis_content.hxx index ef7503a0dfbe..e80a6d278bf3 100644 --- a/ucb/source/ucp/cmis/cmis_content.hxx +++ b/ucb/source/ucp/cmis/cmis_content.hxx @@ -29,6 +29,8 @@ #ifndef CMIS_CONTENT_HXX #define CMIS_CONTENT_HXX +#include "cmis_url.hxx" + #include <com/sun/star/io/XInputStream.hpp> #include <com/sun/star/io/XOutputStream.hpp> #include <com/sun/star/ucb/ContentCreationException.hpp> @@ -68,9 +70,18 @@ class Content : public ::ucbhelper::ContentImplHelper, public com::sun::star::uc private: ContentProvider* m_pProvider; libcmis::Session* m_pSession; - libcmis::CmisObjectPtr m_pObject; + libcmis::ObjectPtr m_pObject; + rtl::OUString m_sObjectId; + rtl::OUString m_sURL; + rtl::OUString m_sBindingUrl; + + // Members to be set for non-persistent content + bool m_bTransient; + libcmis::ObjectTypePtr m_pObjectType; + std::map< std::string, libcmis::PropertyPtr > m_pObjectProps; bool isFolder(const com::sun::star::uno::Reference< com::sun::star::ucb::XCommandEnvironment >& xEnv); + void setCmisProperty( std::string sName, std::string sValue ); com::sun::star::uno::Any getBadArgExcept(); @@ -112,6 +123,9 @@ private: sal_Bool exchangeIdentity(const com::sun::star::uno::Reference< com::sun::star::ucb::XContentIdentifier >& xNewId); + void resetAuthProvider( const com::sun::star::uno::Reference< com::sun::star::ucb::XCommandEnvironment >& xEnv ); + libcmis::ObjectPtr getObject( ); + public: Content( const com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >& rxSMgr, ContentProvider *pProvider, diff --git a/ucb/source/ucp/cmis/cmis_provider.cxx b/ucb/source/ucp/cmis/cmis_provider.cxx index f733cf0ea22a..a13e9f777ff1 100644 --- a/ucb/source/ucp/cmis/cmis_provider.cxx +++ b/ucb/source/ucp/cmis/cmis_provider.cxx @@ -45,12 +45,6 @@ ContentProvider::queryContent( throw( com::sun::star::ucb::IllegalIdentifierException, uno::RuntimeException ) { -#if OSL_DEBUG_LEVEL > 1 - fprintf(stderr, "QueryContent: '%s'\n", - rtl::OUStringToOString - (Identifier->getContentIdentifier(), RTL_TEXTENCODING_UTF8).getStr()); -#endif - osl::MutexGuard aGuard( m_aMutex ); // Check, if a content with given id already exists... @@ -60,7 +54,8 @@ ContentProvider::queryContent( try { - xContent = new ::cmis::Content(m_xSMgr, this, Identifier); + xContent = new ::cmis::Content( m_xSMgr, this, Identifier ); + registerNewContent( xContent ); } catch ( com::sun::star::ucb::ContentCreationException const & ) { @@ -73,14 +68,36 @@ ContentProvider::queryContent( return xContent; } +libcmis::Session* ContentProvider::getSession( const rtl::OUString& sBindingUrl ) +{ + libcmis::Session* pSession = NULL; + std::map< rtl::OUString, libcmis::Session* >::iterator it = m_aSessionCache.find( sBindingUrl ); + if ( it != m_aSessionCache.end( ) ) + { + pSession = it->second; + } + return pSession; +} + +void ContentProvider::registerSession( const rtl::OUString& sBindingUrl, libcmis::Session* pSession ) +{ + m_aSessionCache.insert( std::pair< rtl::OUString, libcmis::Session* >( sBindingUrl, pSession ) ); +} + ContentProvider::ContentProvider( const uno::Reference< lang::XMultiServiceFactory >& rSMgr ) : ::ucbhelper::ContentProviderImplHelper( rSMgr ) { +#if OSL_DEBUG_LEVEL > 1 + fprintf(stderr, "ContentProvider::ContentProvider( )\n" ); +#endif } ContentProvider::~ContentProvider() { +#if OSL_DEBUG_LEVEL > 1 + fprintf(stderr, "ContentProvider::~ContentProvider( )\n" ); +#endif } XINTERFACE_IMPL_3( ContentProvider, diff --git a/ucb/source/ucp/cmis/cmis_provider.hxx b/ucb/source/ucp/cmis/cmis_provider.hxx index 090cde0f1ddf..2ade10052725 100644 --- a/ucb/source/ucp/cmis/cmis_provider.hxx +++ b/ucb/source/ucp/cmis/cmis_provider.hxx @@ -31,12 +31,16 @@ #include <com/sun/star/beans/Property.hpp> #include <ucbhelper/providerhelper.hxx> +#include <libcmis/session.hxx> namespace cmis { class ContentProvider : public ::ucbhelper::ContentProviderImplHelper { +private: + std::map< rtl::OUString, libcmis::Session* > m_aSessionCache; + public: ContentProvider( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& rSMgr ); @@ -58,6 +62,9 @@ public: ::com::sun::star::ucb::XContentIdentifier >& Identifier ) throw( ::com::sun::star::ucb::IllegalIdentifierException, ::com::sun::star::uno::RuntimeException ); + + libcmis::Session* getSession( const rtl::OUString& sBindingUrl ); + void registerSession( const rtl::OUString& sBindingUrl, libcmis::Session* pSession ); }; } diff --git a/ucb/source/ucp/cmis/cmis_url.cxx b/ucb/source/ucp/cmis/cmis_url.cxx index 92a6f7e24435..655518d58365 100644 --- a/ucb/source/ucp/cmis/cmis_url.cxx +++ b/ucb/source/ucp/cmis/cmis_url.cxx @@ -27,7 +27,6 @@ */ #include <libcmis/session-factory.hxx> -#include <tools/urlobj.hxx> #include "cmis_url.hxx" @@ -38,17 +37,17 @@ using namespace std; namespace cmis { - URL::URL( rtl::OUString const & urlStr ) + URL::URL( rtl::OUString const & urlStr ) : + m_aUrl( urlStr ) { - INetURLObject url( urlStr ); - string bindingUrl( "http://" ); - bindingUrl += OUSTR_TO_STDSTR( url.GetHostPort( ) ); - bindingUrl += OUSTR_TO_STDSTR( url.GetURLPath( ) ); + rtl::OUString bindingUrl( "http://" ); + bindingUrl += m_aUrl.GetHostPort( ); + bindingUrl += m_aUrl.GetURLPath( ); m_sBindingUrl = bindingUrl; // Split the query into bits and locate the repo-id key - rtl::OUString query = url.GetParam( ); + rtl::OUString query = m_aUrl.GetParam( ); while ( !query.isEmpty() ) { sal_Int32 nPos = query.indexOfAsciiL( "&", 1 ); @@ -65,8 +64,8 @@ namespace cmis } sal_Int32 nEqPos = segment.indexOfAsciiL( "=", 1 ); - string key = OUSTR_TO_STDSTR( segment.copy( 0, nEqPos ) ); - string value = OUSTR_TO_STDSTR( segment.copy( nEqPos +1 ) ); + rtl::OUString key = segment.copy( 0, nEqPos ); + rtl::OUString value = segment.copy( nEqPos +1 ); if ( key == "repo-id" ) m_sRepositoryId = value; @@ -79,16 +78,40 @@ namespace cmis map< int, string > URL::getSessionParams( ) { map< int, string > params; - params[ATOMPUB_URL] = m_sBindingUrl; - params[REPOSITORY_ID] = m_sRepositoryId; + params[ATOMPUB_URL] = OUSTR_TO_STDSTR( m_sBindingUrl ); + params[REPOSITORY_ID] = OUSTR_TO_STDSTR( m_sRepositoryId ); + params[USERNAME] = OUSTR_TO_STDSTR( m_aUrl.GetUser() ); + params[PASSWORD] = OUSTR_TO_STDSTR( m_aUrl.GetPass() ); return params; } - string URL::getObjectId( ) + rtl::OUString URL::getObjectId( ) { return m_aQuery["id"]; } + + rtl::OUString URL::getBindingUrl( ) + { + return m_sBindingUrl; + } + + void URL::setObjectId( rtl::OUString sId ) + { + m_aQuery["id"] = sId; + updateUrlQuery( ); + } + + rtl::OUString URL::asString( ) + { + return m_aUrl.GetMainURL( INetURLObject::NO_DECODE ); + } + + void URL::updateUrlQuery( ) + { + rtl::OUString sParam = "repo-id=" + m_sRepositoryId + "&id=" + m_aQuery["id"]; + m_aUrl.SetParam( sParam ); + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/cmis/cmis_url.hxx b/ucb/source/ucp/cmis/cmis_url.hxx index 1859102fa59e..18d13f166f37 100644 --- a/ucb/source/ucp/cmis/cmis_url.hxx +++ b/ucb/source/ucp/cmis/cmis_url.hxx @@ -32,22 +32,32 @@ #include <string> #include <rtl/ustring.hxx> +#include <tools/urlobj.hxx> namespace cmis { class URL { private: - std::string m_sBindingUrl; - std::string m_sRepositoryId; + INetURLObject m_aUrl; + rtl::OUString m_sBindingUrl; + rtl::OUString m_sRepositoryId; - std::map< std::string, std::string > m_aQuery; + std::map< rtl::OUString, rtl::OUString > m_aQuery; public: URL( rtl::OUString const & urlStr ); std::map< int, std::string > getSessionParams( ); - std::string getObjectId( ); + rtl::OUString getObjectId( ); + rtl::OUString getBindingUrl( ); + void setObjectId( rtl::OUString sId ); + + rtl::OUString asString( ); + + private: + + void updateUrlQuery( ); }; } |