1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * Version: MPL 1.1 / GPLv3+ / LGPLv3+
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License or as specified alternatively below. You may obtain a copy of
8 * the License at http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * Major Contributor(s):
16 * [ Copyright (C) 2011 SUSE <cbosdonnat@suse.com> (initial developer) ]
18 * All Rights Reserved.
20 * For minor contributions see the git repository.
22 * Alternatively, the contents of this file may be used under the terms of
23 * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
24 * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
25 * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
26 * instead of those above.
31 #include <com/sun/star/beans/PropertyAttribute.hpp>
32 #include <com/sun/star/beans/PropertyValue.hpp>
33 #include <com/sun/star/beans/XPropertySetInfo.hpp>
34 #include <com/sun/star/io/XActiveDataSink.hpp>
35 #include <com/sun/star/io/XActiveDataStreamer.hpp>
36 #include <com/sun/star/lang/IllegalAccessException.hpp>
37 #include <com/sun/star/task/InteractionClassification.hpp>
38 #include <com/sun/star/ucb/ContentInfo.hpp>
39 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
40 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
41 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
42 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
43 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
44 #include <com/sun/star/ucb/NameClash.hpp>
45 #include <com/sun/star/ucb/NameClashException.hpp>
46 #include <com/sun/star/ucb/OpenMode.hpp>
47 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
48 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
49 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
50 #include <com/sun/star/ucb/XCommandInfo.hpp>
51 #include <com/sun/star/ucb/XDynamicResultSet.hpp>
53 #include <libcmis/document.hxx>
55 #include <ucbhelper/cancelcommandexecution.hxx>
56 #include <ucbhelper/contentidentifier.hxx>
57 #include <ucbhelper/std_inputstream.hxx>
58 #include <ucbhelper/std_outputstream.hxx>
59 #include <ucbhelper/propertyvalueset.hxx>
60 #include <ucbhelper/simpleauthenticationrequest.hxx>
62 #include "cmis_content.hxx"
63 #include "cmis_provider.hxx"
64 #include "cmis_resultset.hxx"
66 #define OUSTR_TO_STDSTR(s) string( rtl::OUStringToOString( s, RTL_TEXTENCODING_UTF8 ).getStr() )
67 #define STD_TO_OUSTR( str ) rtl::OUString( str.c_str(), str.length( ), RTL_TEXTENCODING_UTF8 )
69 using namespace com::sun::star
;
74 class AuthProvider
: public libcmis::AuthProvider
76 const com::sun::star::uno::Reference
< com::sun::star::ucb::XCommandEnvironment
>& m_xEnv
;
78 rtl::OUString m_sBindingUrl
;
81 AuthProvider ( const com::sun::star::uno::Reference
<
82 com::sun::star::ucb::XCommandEnvironment
>& xEnv
,
84 rtl::OUString sBindingUrl
):
85 m_xEnv( xEnv
), m_sUrl( sUrl
), m_sBindingUrl( sBindingUrl
) { }
87 bool authenticationQuery( string
& username
, string
& password
);
90 bool AuthProvider::authenticationQuery( string
& username
, string
& password
)
94 uno::Reference
< task::XInteractionHandler
> xIH
95 = m_xEnv
->getInteractionHandler();
99 rtl::Reference
< ucbhelper::SimpleAuthenticationRequest
> xRequest
100 = new ucbhelper::SimpleAuthenticationRequest(
101 m_sUrl
, m_sBindingUrl
, ::rtl::OUString(),
102 STD_TO_OUSTR( username
),
103 STD_TO_OUSTR( password
),
104 ::rtl::OUString(), true, false );
105 xIH
->handle( xRequest
.get() );
107 rtl::Reference
< ucbhelper::InteractionContinuation
> xSelection
108 = xRequest
->getSelection();
110 if ( xSelection
.is() )
112 // Handler handled the request.
113 uno::Reference
< task::XInteractionAbort
> xAbort(
114 xSelection
.get(), uno::UNO_QUERY
);
117 const rtl::Reference
<
118 ucbhelper::InteractionSupplyAuthentication
> & xSupp
119 = xRequest
->getAuthenticationSupplier();
121 username
= OUSTR_TO_STDSTR( xSupp
->getUserName() );
122 password
= OUSTR_TO_STDSTR( xSupp
->getPassword() );
132 util::DateTime
lcl_boostToUnoTime( boost::posix_time::ptime boostTime
)
134 util::DateTime unoTime
;
135 unoTime
.Year
= boostTime
.date().year();
136 unoTime
.Month
= boostTime
.date().month();
137 unoTime
.Day
= boostTime
.date().day();
138 unoTime
.Hours
= boostTime
.time_of_day().hours();
139 unoTime
.Minutes
= boostTime
.time_of_day().minutes();
140 unoTime
.Seconds
= boostTime
.time_of_day().seconds();
142 long total_milli
= boostTime
.time_of_day().total_milliseconds( );
143 long milli
= total_milli
- boostTime
.time_of_day().total_seconds( );
144 long hundredthSeconds
= milli
/ 10;
146 unoTime
.HundredthSeconds
= hundredthSeconds
;
154 Content::Content( const uno::Reference
< lang::XMultiServiceFactory
>& rxSMgr
,
155 ContentProvider
*pProvider
, const uno::Reference
< ucb::XContentIdentifier
>& Identifier
)
156 throw ( ucb::ContentCreationException
)
157 : ContentImplHelper( rxSMgr
, pProvider
, Identifier
),
158 m_pProvider( pProvider
),
160 m_bTransient( false )
162 // Split the URL into bits
163 m_sURL
= m_xIdentifier
->getContentIdentifier( );
164 cmis::URL
url( m_sURL
);
165 SAL_INFO( "cmisucp", "Content::Content() " << m_sURL
);
167 // Look for a cached session, key is binding url + repo id
168 rtl::OUString sSessionId
= url
.getBindingUrl( ) + url
.getRepositoryId( );
169 m_pSession
= pProvider
->getSession( sSessionId
);
170 if ( NULL
== m_pSession
)
172 // Initiate a CMIS session and register it as we found nothing
173 m_pSession
= libcmis::SessionFactory::createSession( url
.getSessionParams( ) );
174 pProvider
->registerSession( sSessionId
, m_pSession
);
177 m_sObjectPath
= url
.getObjectPath( );
178 m_sObjectId
= url
.getObjectId( );
179 m_sBindingUrl
= url
.getBindingUrl( );
182 Content::Content( const uno::Reference
< lang::XMultiServiceFactory
>& rxSMgr
, ContentProvider
*pProvider
,
183 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
185 throw ( ucb::ContentCreationException
)
186 : ContentImplHelper( rxSMgr
, pProvider
, Identifier
),
187 m_pProvider( pProvider
),
191 // Split the URL into bits
192 m_sURL
= m_xIdentifier
->getContentIdentifier( );
193 cmis::URL
url( m_sURL
);
194 SAL_INFO( "cmisucp", "Content::Content() " << m_sURL
);
196 // Look for a cached session, key is binding url + repo id
197 rtl::OUString sSessionId
= url
.getBindingUrl( ) + url
.getRepositoryId( );
198 m_pSession
= pProvider
->getSession( sSessionId
);
199 if ( NULL
== m_pSession
)
201 // Initiate a CMIS session and register it as we found nothing
202 m_pSession
= libcmis::SessionFactory::createSession( url
.getSessionParams( ) );
203 pProvider
->registerSession( sSessionId
, m_pSession
);
206 m_sObjectPath
= url
.getObjectPath( );
207 m_sObjectId
= url
.getObjectId( );
208 m_sBindingUrl
= url
.getBindingUrl( );
210 // Get the object type
211 string typeId
= bIsFolder
? "cmis:folder" : "cmis:document";
212 m_pObjectType
= m_pSession
->getType( typeId
);
219 libcmis::ObjectPtr
Content::getObject( ) throw ( libcmis::Exception
)
221 if ( !m_pObject
.get() )
223 if ( !m_sObjectPath
.isEmpty( ) )
224 m_pObject
= m_pSession
->getObjectByPath( OUSTR_TO_STDSTR( m_sObjectPath
) );
225 else if (!m_sObjectId
.isEmpty( ) )
226 m_pObject
= m_pSession
->getObject( OUSTR_TO_STDSTR( m_sObjectId
) );
229 m_pObject
= m_pSession
->getRootFolder( );
231 m_sObjectId
= rtl::OUString( );
238 void Content::resetAuthProvider( const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
240 libcmis::AuthProviderPtr
authProvider( new AuthProvider( xEnv
, m_sURL
, m_sBindingUrl
) );
241 m_pSession
->setAuthenticationProvider( authProvider
);
244 bool Content::isFolder(const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
246 bool bIsFolder
= false;
249 resetAuthProvider( xEnv
);
250 bIsFolder
= getObject( )->getBaseType( ) == "cmis:folder";
252 catch ( const libcmis::Exception
& e
)
254 SAL_INFO( "cmisucp", "Unexpected libcmis exception: " << e
.what( ) );
255 ucbhelper::cancelCommandExecution(
256 ucb::IOErrorCode_GENERAL
,
257 uno::Sequence
< uno::Any
>( 0 ),
259 rtl::OUString::createFromAscii( e
.what() ) );
264 uno::Any
Content::getBadArgExcept()
266 return uno::makeAny( lang::IllegalArgumentException(
267 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Wrong argument type!")),
268 static_cast< cppu::OWeakObject
* >( this ), -1) );
271 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
272 const uno::Sequence
< beans::Property
>& rProperties
,
273 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
275 resetAuthProvider( xEnv
);
277 rtl::Reference
< ::ucbhelper::PropertyValueSet
> xRow
= new ::ucbhelper::PropertyValueSet( m_xSMgr
);
280 const beans::Property
* pProps
;
282 nProps
= rProperties
.getLength();
283 pProps
= rProperties
.getConstArray();
285 for( sal_Int32 n
= 0; n
< nProps
; ++n
)
287 const beans::Property
& rProp
= pProps
[ n
];
291 if ( rProp
.Name
== "IsDocument" )
295 xRow
->appendBoolean( rProp
, getObject()->getBaseType( ) == "cmis:document" );
297 catch ( const libcmis::Exception
& )
299 if ( m_pObjectType
.get( ) )
300 xRow
->appendBoolean( rProp
, m_pObjectType
->getBaseType()->getId( ) == "cmis:document" );
302 xRow
->appendVoid( rProp
);
305 else if ( rProp
.Name
== "IsFolder" )
309 xRow
->appendBoolean( rProp
, getObject()->getBaseType( ) == "cmis:folder" );
311 catch ( const libcmis::Exception
& )
313 if ( m_pObjectType
.get( ) )
314 xRow
->appendBoolean( rProp
, m_pObjectType
->getBaseType()->getId( ) == "cmis:folder" );
316 xRow
->appendVoid( rProp
);
319 else if ( rProp
.Name
== "Title" )
321 rtl::OUString sTitle
;
324 sTitle
= STD_TO_OUSTR( getObject()->getName() );
326 catch ( const libcmis::Exception
& )
328 if ( m_pObjectProps
.size() > 0 )
330 map
< string
, libcmis::PropertyPtr
>::iterator it
= m_pObjectProps
.find( "cmis:name" );
331 if ( it
!= m_pObjectProps
.end( ) )
333 vector
< string
> values
= it
->second
->getStrings( );
334 if ( values
.size() > 0 )
335 sTitle
= STD_TO_OUSTR( values
.front( ) );
340 // Nothing worked... get it from the path
341 if ( sTitle
.isEmpty( ) )
343 rtl::OUString sPath
= m_sObjectPath
;
345 // Get rid of the trailing slash problem
346 if ( sPath
[ sPath
.getLength( ) - 1 ] == '/' )
347 sPath
= sPath
.copy( 0, sPath
.getLength() - 1 );
349 // Get the last segment
350 sal_Int32 nPos
= sPath
.lastIndexOf( '/' );
352 sTitle
= sPath
.copy( nPos
+ 1 );
355 if ( !sTitle
.isEmpty( ) )
356 xRow
->appendString( rProp
, sTitle
);
358 xRow
->appendVoid( rProp
);
360 else if ( rProp
.Name
== "TitleOnServer" )
365 vector
< string
> paths
= getObject( )->getPaths( );
366 if ( paths
.size( ) > 0 )
367 path
= paths
.front( );
369 path
= getObject()->getName( );
371 xRow
->appendString( rProp
, STD_TO_OUSTR( path
) );
373 catch ( const libcmis::Exception
& )
375 xRow
->appendVoid( rProp
);
378 else if ( rProp
.Name
== "IsReadOnly" )
380 boost::shared_ptr
< libcmis::AllowableActions
> allowableActions
= getObject()->getAllowableActions( );
381 sal_Bool bReadOnly
= sal_False
;
382 if ( !allowableActions
->isAllowed( libcmis::ObjectAction::SetContentStream
) )
383 bReadOnly
= sal_True
;
385 xRow
->appendBoolean( rProp
, bReadOnly
);
387 else if ( rProp
.Name
== "DateCreated" )
389 util::DateTime aTime
= lcl_boostToUnoTime( getObject( )->getCreationDate( ) );
390 xRow
->appendTimestamp( rProp
, aTime
);
392 else if ( rProp
.Name
== "DateModified" )
394 util::DateTime aTime
= lcl_boostToUnoTime( getObject( )->getLastModificationDate( ) );
395 xRow
->appendTimestamp( rProp
, aTime
);
397 else if ( rProp
.Name
== "Size" )
401 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( getObject().get( ) );
402 if ( NULL
!= document
)
403 xRow
->appendLong( rProp
, document
->getContentLength() );
405 xRow
->appendVoid( rProp
);
407 catch ( const libcmis::Exception
& )
409 xRow
->appendVoid( rProp
);
412 else if ( rProp
.Name
== "CreatableContentsInfo" )
414 xRow
->appendObject( rProp
, uno::makeAny( queryCreatableContentsInfo( xEnv
) ) );
416 else if ( rProp
.Name
== "MediaType" )
420 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( getObject().get( ) );
421 if ( NULL
!= document
)
422 xRow
->appendString( rProp
, STD_TO_OUSTR( document
->getContentType() ) );
424 xRow
->appendVoid( rProp
);
426 catch ( const libcmis::Exception
& )
428 xRow
->appendVoid( rProp
);
432 SAL_INFO( "cmisucp", "Looking for unsupported property " << rProp
.Name
);
434 catch (const libcmis::Exception
&)
436 xRow
->appendVoid( rProp
);
440 return uno::Reference
< sdbc::XRow
>( xRow
.get() );
443 bool Content::exists( )
448 if ( !m_sObjectPath
.isEmpty( ) )
449 m_pSession
->getObjectByPath( OUSTR_TO_STDSTR( m_sObjectPath
) );
450 else if ( !m_sObjectId
.isEmpty( ) )
451 m_pSession
->getObject( OUSTR_TO_STDSTR( m_sObjectId
) );
452 // No need to handle the root folder case... how can it not exists?
454 catch ( const libcmis::Exception
& )
462 void Content::queryChildren( ContentRefList
& /*rChildren*/ )
464 SAL_INFO( "cmisucp", "TODO - Content::queryChildren()" );
468 uno::Any
Content::open(const ucb::OpenCommandArgument2
& rOpenCommand
,
469 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
470 throw( uno::Exception
)
472 bool bIsFolder
= isFolder( xEnv
);
474 // Handle the case of the non-existing file
477 uno::Sequence
< uno::Any
> aArgs( 1 );
478 aArgs
[ 0 ] <<= m_xIdentifier
->getContentIdentifier();
479 uno::Any aErr
= uno::makeAny(
480 ucb::InteractiveAugmentedIOException(rtl::OUString(), static_cast< cppu::OWeakObject
* >( this ),
481 task::InteractionClassification_ERROR
,
482 bIsFolder
? ucb::IOErrorCode_NOT_EXISTING_PATH
: ucb::IOErrorCode_NOT_EXISTING
, aArgs
)
485 ucbhelper::cancelCommandExecution(aErr
, xEnv
);
490 sal_Bool bOpenFolder
= (
491 ( rOpenCommand
.Mode
== ucb::OpenMode::ALL
) ||
492 ( rOpenCommand
.Mode
== ucb::OpenMode::FOLDERS
) ||
493 ( rOpenCommand
.Mode
== ucb::OpenMode::DOCUMENTS
)
496 if ( bOpenFolder
&& bIsFolder
)
498 uno::Reference
< ucb::XDynamicResultSet
> xSet
499 = new DynamicResultSet(m_xSMgr
, this, rOpenCommand
, xEnv
);
502 else if ( rOpenCommand
.Sink
.is() )
505 ( rOpenCommand
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE
) ||
506 ( rOpenCommand
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE
)
509 ucbhelper::cancelCommandExecution(
510 uno::makeAny ( ucb::UnsupportedOpenModeException
511 ( rtl::OUString(), static_cast< cppu::OWeakObject
* >( this ),
512 sal_Int16( rOpenCommand
.Mode
) ) ),
516 if ( !feedSink( rOpenCommand
.Sink
, xEnv
) )
518 // Note: rOpenCommand.Sink may contain an XStream
519 // implementation. Support for this type of
520 // sink is optional...
521 SAL_INFO( "cmisucp", "Failed to copy data to sink" );
523 ucbhelper::cancelCommandExecution(
524 uno::makeAny (ucb::UnsupportedDataSinkException
525 ( rtl::OUString(), static_cast< cppu::OWeakObject
* >( this ),
526 rOpenCommand
.Sink
) ),
531 SAL_INFO( "cmisucp", "Open falling through ..." );
536 void Content::transfer( const ucb::TransferInfo
& rTransferInfo
,
537 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
538 throw( uno::Exception
)
540 // If the source isn't on the same CMIS repository, then simply copy
541 INetURLObject
aSourceUrl( rTransferInfo
.SourceURL
);
542 if ( aSourceUrl
.GetProtocol() != INET_PROT_CMIS_ATOM
)
544 rtl::OUString sSrcBindingUrl
= URL( rTransferInfo
.SourceURL
).getBindingUrl( );
545 if ( sSrcBindingUrl
!= m_sBindingUrl
)
547 ucbhelper::cancelCommandExecution(
549 ucb::InteractiveBadTransferURLException(
550 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
551 "Unsupported URL scheme!" )),
552 static_cast< cppu::OWeakObject
* >( this ) ) ),
557 SAL_INFO( "cmisucp", "TODO - Content::transfer()" );
560 void Content::insert( const uno::Reference
< io::XInputStream
> & xInputStream
,
561 sal_Bool bReplaceExisting
, const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
562 throw( uno::Exception
)
564 if ( !xInputStream
.is() )
566 ucbhelper::cancelCommandExecution( uno::makeAny
567 ( ucb::MissingInputStreamException
568 ( rtl::OUString(), static_cast< cppu::OWeakObject
* >( this ) ) ),
572 // For transient content, the URL is the one of the parent
575 rtl::OUString sNewPath
;
577 // Try to get the object from the server if there is any
578 libcmis::Folder
* pFolder
= NULL
;
581 pFolder
= dynamic_cast< libcmis::Folder
* >( getObject( ).get( ) );
583 catch ( const libcmis::Exception
& )
587 if ( pFolder
!= NULL
)
589 map
< string
, libcmis::PropertyPtr
>::iterator it
= m_pObjectProps
.find( "cmis:name" );
590 if ( it
== m_pObjectProps
.end( ) )
592 ucbhelper::cancelCommandExecution( uno::makeAny
593 ( uno::RuntimeException( "Missing name property",
594 static_cast< cppu::OWeakObject
* >( this ) ) ),
597 string newName
= it
->second
->getStrings( ).front( );
598 string newPath
= pFolder
->getPath( );
599 if ( newPath
[ newPath
.size( ) - 1 ] != '/' )
603 libcmis::ObjectPtr object
;
606 object
= m_pSession
->getObjectByPath( newPath
);
607 sNewPath
= STD_TO_OUSTR( newPath
);
609 catch ( const libcmis::Exception
& )
611 // Nothing matched the path
614 if ( NULL
!= object
.get( ) )
616 // Are the base type matching?
617 if ( object
->getBaseType( ) != m_pObjectType
->getBaseType( )->getId() )
619 ucbhelper::cancelCommandExecution( uno::makeAny
620 ( uno::RuntimeException( "Can't change a folder into a document and vice-versa.",
621 static_cast< cppu::OWeakObject
* >( this ) ) ),
625 // Update the existing object if it's a document
626 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( object
.get( ) );
627 if ( NULL
!= document
)
629 string sMime
= document
->getContentType( );
630 boost::shared_ptr
< ostream
> pOut( new ostringstream ( ios_base::binary
| ios_base::in
| ios_base::out
) );
631 uno::Reference
< io::XOutputStream
> xOutput
= new ucbhelper::StdOutputStream( pOut
);
632 copyData( xInputStream
, xOutput
);
633 document
->setContentStream( pOut
, sMime
, bReplaceExisting
);
638 // We need to create a brand new object... either folder or document
639 bool bIsFolder
= m_pObjectType
->getBaseType( )->getId( ) == "cmis:folder";
640 setCmisProperty( "cmis:objectTypeId", m_pObjectType
->getId( ) );
644 libcmis::FolderPtr pNew
= pFolder
->createFolder( m_pObjectProps
);
645 sNewPath
= STD_TO_OUSTR( newPath
);
649 boost::shared_ptr
< ostream
> pOut( new ostringstream ( ios_base::binary
| ios_base::in
| ios_base::out
) );
650 uno::Reference
< io::XOutputStream
> xOutput
= new ucbhelper::StdOutputStream( pOut
);
651 copyData( xInputStream
, xOutput
);
652 libcmis::DocumentPtr pNew
= pFolder
->createDocument( m_pObjectProps
, pOut
, string() );
653 sNewPath
= STD_TO_OUSTR( newPath
);
657 if ( !sNewPath
.isEmpty( ) )
659 // Update the current content: it's no longer transient
660 m_sObjectPath
= sNewPath
;
662 aUrl
.setObjectPath( m_sObjectPath
);
663 m_sURL
= aUrl
.asString( );
665 m_pObjectType
.reset( );
666 m_pObjectProps
.clear( );
667 m_bTransient
= false;
675 const int TRANSFER_BUFFER_SIZE
= 65536;
677 void Content::copyData(
678 uno::Reference
< io::XInputStream
> xIn
,
679 uno::Reference
< io::XOutputStream
> xOut
)
681 uno::Sequence
< sal_Int8
> theData( TRANSFER_BUFFER_SIZE
);
683 while ( xIn
->readBytes( theData
, TRANSFER_BUFFER_SIZE
) > 0 )
684 xOut
->writeBytes( theData
);
689 uno::Sequence
< uno::Any
> Content::setPropertyValues(
690 const uno::Sequence
< beans::PropertyValue
>& rValues
,
691 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
695 // Get the already set properties if possible
696 if ( !m_bTransient
&& getObject( ).get( ) )
698 m_pObjectProps
= getObject()->getProperties( );
699 m_pObjectType
= getObject()->getTypeDescription();
702 catch ( const libcmis::Exception
& e
)
704 SAL_INFO( "cmisucp", "Unexpected libcmis exception: " << e
.what( ) );
705 ucbhelper::cancelCommandExecution(
706 ucb::IOErrorCode_GENERAL
,
707 uno::Sequence
< uno::Any
>( 0 ),
709 rtl::OUString::createFromAscii( e
.what() ) );
712 sal_Int32 nCount
= rValues
.getLength();
713 uno::Sequence
< uno::Any
> aRet( nCount
);
715 bool bChanged
= false;
716 const beans::PropertyValue
* pValues
= rValues
.getConstArray();
717 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
719 const beans::PropertyValue
& rValue
= pValues
[ n
];
720 if ( rValue
.Name
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) ||
721 rValue
.Name
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) ||
722 rValue
.Name
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) ||
723 rValue
.Name
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) ||
724 rValue
.Name
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Size" ) ) ||
725 rValue
.Name
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) )
727 lang::IllegalAccessException
e ( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Property is read-only!")),
728 static_cast< cppu::OWeakObject
* >( this ) );
731 else if ( rValue
.Name
== "Title" )
733 rtl::OUString aNewTitle
;
734 if (!( rValue
.Value
>>= aNewTitle
))
736 aRet
[ n
] <<= beans::IllegalTypeException
737 ( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Property value has wrong type!")),
738 static_cast< cppu::OWeakObject
* >( this ) );
742 if ( aNewTitle
.getLength() <= 0 )
744 aRet
[ n
] <<= lang::IllegalArgumentException
745 ( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Empty title not allowed!")),
746 static_cast< cppu::OWeakObject
* >( this ), -1 );
751 setCmisProperty( "cmis:name", OUSTR_TO_STDSTR( aNewTitle
) );
756 SAL_INFO( "cmisucp", "Couln't set property: " << rValue
.Name
);
757 lang::IllegalAccessException
e ( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Property is read-only!")),
758 static_cast< cppu::OWeakObject
* >( this ) );
765 if ( !m_bTransient
&& bChanged
)
767 getObject()->updateProperties();
770 catch ( const libcmis::Exception
& e
)
772 SAL_INFO( "cmisucp", "Unexpected libcmis exception: " << e
.what( ) );
773 ucbhelper::cancelCommandExecution(
774 ucb::IOErrorCode_GENERAL
,
775 uno::Sequence
< uno::Any
>( 0 ),
777 rtl::OUString::createFromAscii( e
.what() ) );
783 sal_Bool
Content::feedSink( uno::Reference
< uno::XInterface
> xSink
,
784 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
789 uno::Reference
< io::XOutputStream
> xOut
= uno::Reference
< io::XOutputStream
>(xSink
, uno::UNO_QUERY
);
790 uno::Reference
< io::XActiveDataSink
> xDataSink
= uno::Reference
< io::XActiveDataSink
>(xSink
, uno::UNO_QUERY
);
791 uno::Reference
< io::XActiveDataStreamer
> xDataStreamer
= uno::Reference
< io::XActiveDataStreamer
>( xSink
, uno::UNO_QUERY
);
793 if ( !xOut
.is() && !xDataSink
.is() && ( !xDataStreamer
.is() || !xDataStreamer
->getStream().is() ) )
796 if ( xDataStreamer
.is() && !xOut
.is() )
797 xOut
= xDataStreamer
->getStream()->getOutputStream();
801 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( getObject().get() );
802 boost::shared_ptr
< istream
> aIn
= document
->getContentStream( );
804 uno::Reference
< io::XInputStream
> xIn
= new ucbhelper::StdInputStream( aIn
);
808 if ( xDataSink
.is() )
809 xDataSink
->setInputStream( xIn
);
810 else if ( xOut
.is() )
811 copyData( xIn
, xOut
);
813 catch ( const libcmis::Exception
& e
)
815 SAL_INFO( "cmisucp", "Unexpected libcmis exception: " << e
.what( ) );
816 ucbhelper::cancelCommandExecution(
817 ucb::IOErrorCode_GENERAL
,
818 uno::Sequence
< uno::Any
>( 0 ),
820 rtl::OUString::createFromAscii( e
.what() ) );
826 sal_Bool
Content::exchangeIdentity( const uno::Reference
< ucb::XContentIdentifier
>& /*xNewId*/ )
828 sal_Bool bRet
= sal_False
;
829 SAL_INFO( "cmisucp", "TODO - Content::exchangeIdentity()" );
835 uno::Sequence
< beans::Property
> Content::getProperties(
836 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
838 resetAuthProvider( xEnv
);
840 static const beans::Property aGenericProperties
[] =
842 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDocument" ) ),
843 -1, getCppuBooleanType(),
844 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
845 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ),
846 -1, getCppuBooleanType(),
847 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
848 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ),
849 -1, getCppuType( static_cast< const rtl::OUString
* >( 0 ) ),
850 beans::PropertyAttribute::BOUND
),
851 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TitleOnServer" ) ),
852 -1, getCppuType( static_cast< const rtl::OUString
* >( 0 ) ),
853 beans::PropertyAttribute::BOUND
),
854 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsReadOnly" ) ),
855 -1, getCppuBooleanType(),
856 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
857 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DateCreated" ) ),
858 -1, getCppuType( static_cast< const util::DateTime
* >( 0 ) ),
859 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
860 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DateModified" ) ),
861 -1, getCppuType( static_cast< const util::DateTime
* >( 0 ) ),
862 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
863 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Size" ) ),
864 -1, getCppuType( static_cast< const sal_Int64
* >( 0 ) ),
865 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
866 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CreatableContentsInfo" ) ),
867 -1, getCppuType( static_cast< const uno::Sequence
< ucb::ContentInfo
> * >( 0 ) ),
868 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
869 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ),
870 -1, getCppuType( static_cast< const rtl::OUString
* >( 0 ) ),
871 beans::PropertyAttribute::BOUND
),
874 const int nProps
= SAL_N_ELEMENTS(aGenericProperties
);
875 return uno::Sequence
< beans::Property
> ( aGenericProperties
, nProps
);
878 uno::Sequence
< ucb::CommandInfo
> Content::getCommands(
879 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
881 resetAuthProvider( xEnv
);
883 static ucb::CommandInfo aCommandInfoTable
[] =
887 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getCommandInfo" ) ),
888 -1, getCppuVoidType() ),
890 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getPropertySetInfo" ) ),
891 -1, getCppuVoidType() ),
893 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getPropertyValues" ) ),
894 -1, getCppuType( static_cast<uno::Sequence
< beans::Property
> * >( 0 ) ) ),
896 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "setPropertyValues" ) ),
897 -1, getCppuType( static_cast<uno::Sequence
< beans::PropertyValue
> * >( 0 ) ) ),
899 // Optional standard commands
901 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "delete" ) ),
902 -1, getCppuBooleanType() ),
904 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "insert" ) ),
905 -1, getCppuType( static_cast<ucb::InsertCommandArgument
* >( 0 ) ) ),
907 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "open" ) ),
908 -1, getCppuType( static_cast<ucb::OpenCommandArgument2
* >( 0 ) ) ),
910 // Folder Only, omitted if not a folder
912 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "transfer" ) ),
913 -1, getCppuType( static_cast<ucb::TransferInfo
* >( 0 ) ) ),
915 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "createNewContent" ) ),
916 -1, getCppuType( static_cast<ucb::ContentInfo
* >( 0 ) ) )
919 const int nProps
= SAL_N_ELEMENTS(aCommandInfoTable
);
920 return uno::Sequence
< ucb::CommandInfo
>(aCommandInfoTable
, isFolder(xEnv
) ? nProps
: nProps
- 2);
923 ::rtl::OUString
Content::getParentURL( )
927 SAL_INFO( "cmisucp", "Content::getParentURL()" );
932 libcmis::ObjectPtr pObj
= getObject( );
933 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( getObject( ).get( ) );
934 if ( NULL
!= document
)
936 vector
< boost::shared_ptr
< libcmis::Folder
> > parents
= document
->getParents( );
937 if ( parents
.size( ) > 0 )
938 parentPath
= parents
.front( )->getPath( );
942 libcmis::Folder
* folder
= dynamic_cast< libcmis::Folder
* >( getObject( ).get( ) );
943 if ( NULL
!= folder
)
944 parentPath
= folder
->getFolderParent( )->getPath( );
947 catch ( const libcmis::Exception
& )
949 // We may have an exception if we don't have the rights to
953 if ( !parentPath
.empty() )
956 aUrl
.setObjectPath( STD_TO_OUSTR( parentPath
) );
957 sRet
= aUrl
.asString( );
963 XTYPEPROVIDER_COMMON_IMPL( Content
);
965 void SAL_CALL
Content::acquire() throw()
967 ContentImplHelper::acquire();
970 void SAL_CALL
Content::release() throw()
972 ContentImplHelper::release();
975 uno::Any SAL_CALL
Content::queryInterface( const uno::Type
& rType
) throw ( uno::RuntimeException
)
977 uno::Any aRet
= cppu::queryInterface( rType
, static_cast< ucb::XContentCreator
* >( this ) );
978 return aRet
.hasValue() ? aRet
: ContentImplHelper::queryInterface(rType
);
981 rtl::OUString SAL_CALL
Content::getImplementationName() throw( uno::RuntimeException
)
983 return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.CmisContent"));
986 uno::Sequence
< rtl::OUString
> SAL_CALL
Content::getSupportedServiceNames()
987 throw( uno::RuntimeException
)
989 uno::Sequence
< rtl::OUString
> aSNS( 1 );
990 aSNS
.getArray()[ 0 ] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.ucb.CmisContent"));
994 rtl::OUString SAL_CALL
Content::getContentType() throw( uno::RuntimeException
)
996 return isFolder(uno::Reference
< ucb::XCommandEnvironment
>())
997 ? rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( CMIS_FOLDER_TYPE
))
998 : rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( CMIS_FILE_TYPE
));
1001 uno::Any SAL_CALL
Content::execute(
1002 const ucb::Command
& aCommand
,
1003 sal_Int32
/*CommandId*/,
1004 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1005 throw( uno::Exception
, ucb::CommandAbortedException
, uno::RuntimeException
)
1007 SAL_INFO( "cmisucp", "Content::execute( ) - " << aCommand
.Name
);
1008 resetAuthProvider( xEnv
);
1012 if ( aCommand
.Name
== "getPropertyValues" )
1014 uno::Sequence
< beans::Property
> Properties
;
1015 if ( !( aCommand
.Argument
>>= Properties
) )
1016 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1017 aRet
<<= getPropertyValues( Properties
, xEnv
);
1019 else if ( aCommand
.Name
== "getPropertySetInfo" )
1020 aRet
<<= getPropertySetInfo( xEnv
, sal_False
);
1021 else if ( aCommand
.Name
== "getCommandInfo" )
1022 aRet
<<= getCommandInfo( xEnv
, sal_False
);
1023 else if ( aCommand
.Name
== "open" )
1025 ucb::OpenCommandArgument2 aOpenCommand
;
1026 if ( !( aCommand
.Argument
>>= aOpenCommand
) )
1027 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1028 aRet
= open( aOpenCommand
, xEnv
);
1030 else if ( aCommand
.Name
== "transfer" )
1032 ucb::TransferInfo transferArgs
;
1033 if ( !( aCommand
.Argument
>>= transferArgs
) )
1034 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1035 transfer( transferArgs
, xEnv
);
1037 else if ( aCommand
.Name
== "setPropertyValues" )
1039 uno::Sequence
< beans::PropertyValue
> aProperties
;
1040 if ( !( aCommand
.Argument
>>= aProperties
) || !aProperties
.getLength() )
1041 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1042 aRet
<<= setPropertyValues( aProperties
, xEnv
);
1044 else if (aCommand
.Name
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "createNewContent" ) )
1045 && isFolder( xEnv
) )
1047 ucb::ContentInfo arg
;
1048 if ( !( aCommand
.Argument
>>= arg
) )
1049 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1050 aRet
<<= createNewContent( arg
);
1052 else if ( aCommand
.Name
== "insert" )
1054 ucb::InsertCommandArgument arg
;
1055 if ( !( aCommand
.Argument
>>= arg
) )
1056 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1057 insert( arg
.Data
, arg
.ReplaceExisting
, xEnv
);
1059 else if ( aCommand
.Name
== "delete" )
1063 if ( !isFolder( xEnv
) )
1065 getObject( )->remove( );
1069 libcmis::Folder
* folder
= dynamic_cast< libcmis::Folder
* >( getObject( ).get() );
1070 folder
->removeTree( );
1073 catch ( const libcmis::Exception
& e
)
1075 SAL_INFO( "cmisucp", "Unexpected libcmis exception: " << e
.what( ) );
1076 ucbhelper::cancelCommandExecution(
1077 ucb::IOErrorCode_GENERAL
,
1078 uno::Sequence
< uno::Any
>( 0 ),
1080 rtl::OUString::createFromAscii( e
.what() ) );
1085 SAL_INFO( "cmisucp", "Unknown command to execute" );
1087 ucbhelper::cancelCommandExecution
1088 ( uno::makeAny( ucb::UnsupportedCommandException
1090 static_cast< cppu::OWeakObject
* >( this ) ) ),
1097 void SAL_CALL
Content::abort( sal_Int32
/*CommandId*/ ) throw( uno::RuntimeException
)
1099 SAL_INFO( "cmisucp", "TODO - Content::abort()" );
1100 // TODO Implement me
1103 uno::Sequence
< ucb::ContentInfo
> SAL_CALL
Content::queryCreatableContentsInfo()
1104 throw( uno::RuntimeException
)
1106 return queryCreatableContentsInfo( uno::Reference
< ucb::XCommandEnvironment
>() );
1109 uno::Reference
< ucb::XContent
> SAL_CALL
Content::createNewContent(
1110 const ucb::ContentInfo
& Info
) throw( uno::RuntimeException
)
1112 bool create_document
;
1114 if ( Info
.Type
== CMIS_FILE_TYPE
)
1115 create_document
= true;
1116 else if ( Info
.Type
== CMIS_FOLDER_TYPE
)
1117 create_document
= false;
1120 SAL_INFO( "cmisucp", "Unknown type of content to create" );
1121 return uno::Reference
< ucb::XContent
>();
1124 rtl::OUString sParentURL
= m_xIdentifier
->getContentIdentifier();
1125 URL
aParentURL( sParentURL
);
1127 // Set the parent URL for the transient objects
1128 uno::Reference
< ucb::XContentIdentifier
> xId(new ::ucbhelper::ContentIdentifier(m_xSMgr
, sParentURL
));
1132 return new ::cmis::Content( m_xSMgr
, m_pProvider
, xId
, !create_document
);
1134 catch ( ucb::ContentCreationException
& )
1136 return uno::Reference
< ucb::XContent
>();
1140 uno::Sequence
< uno::Type
> SAL_CALL
Content::getTypes() throw( uno::RuntimeException
)
1142 if ( isFolder( uno::Reference
< ucb::XCommandEnvironment
>() ) )
1144 static cppu::OTypeCollection aFolderCollection
1145 (CPPU_TYPE_REF( lang::XTypeProvider
),
1146 CPPU_TYPE_REF( lang::XServiceInfo
),
1147 CPPU_TYPE_REF( lang::XComponent
),
1148 CPPU_TYPE_REF( ucb::XContent
),
1149 CPPU_TYPE_REF( ucb::XCommandProcessor
),
1150 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
1151 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
1152 CPPU_TYPE_REF( beans::XPropertyContainer
),
1153 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
1154 CPPU_TYPE_REF( container::XChild
),
1155 CPPU_TYPE_REF( ucb::XContentCreator
) );
1156 return aFolderCollection
.getTypes();
1160 static cppu::OTypeCollection aFileCollection
1161 (CPPU_TYPE_REF( lang::XTypeProvider
),
1162 CPPU_TYPE_REF( lang::XServiceInfo
),
1163 CPPU_TYPE_REF( lang::XComponent
),
1164 CPPU_TYPE_REF( ucb::XContent
),
1165 CPPU_TYPE_REF( ucb::XCommandProcessor
),
1166 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
1167 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
1168 CPPU_TYPE_REF( beans::XPropertyContainer
),
1169 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
1170 CPPU_TYPE_REF( container::XChild
) );
1172 return aFileCollection
.getTypes();
1177 uno::Sequence
< ucb::ContentInfo
> Content::queryCreatableContentsInfo(
1178 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1179 throw( uno::RuntimeException
)
1181 resetAuthProvider( xEnv
);
1182 if ( isFolder( xEnv
) )
1184 uno::Sequence
< ucb::ContentInfo
> seq(2);
1186 // Minimum set of props we really need
1187 uno::Sequence
< beans::Property
> props( 1 );
1188 props
[0] = beans::Property(
1189 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Title")),
1191 getCppuType( static_cast< rtl::OUString
* >( 0 ) ),
1192 beans::PropertyAttribute::MAYBEVOID
| beans::PropertyAttribute::BOUND
);
1195 seq
[0].Type
= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( CMIS_FILE_TYPE
));
1196 seq
[0].Attributes
= ( ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
|
1197 ucb::ContentInfoAttribute::KIND_DOCUMENT
);
1198 seq
[0].Properties
= props
;
1201 seq
[1].Type
= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( CMIS_FOLDER_TYPE
));
1202 seq
[1].Attributes
= ucb::ContentInfoAttribute::KIND_FOLDER
;
1203 seq
[1].Properties
= props
;
1209 return uno::Sequence
< ucb::ContentInfo
>();
1213 void Content::setCmisProperty( std::string sName
, std::string sValue
)
1215 if ( m_pObjectType
.get( ) )
1217 map
< string
, libcmis::PropertyPtr
>::iterator propIt
= m_pObjectProps
.find( sName
);
1218 vector
< string
> values
;
1219 values
.push_back( sValue
);
1221 if ( propIt
== m_pObjectProps
.end( ) && m_pObjectType
.get( ) )
1223 map
< string
, libcmis::PropertyTypePtr
> propsTypes
= m_pObjectType
->getPropertiesTypes( );
1224 map
< string
, libcmis::PropertyTypePtr
>::iterator typeIt
= propsTypes
.find( sName
);
1226 if ( typeIt
!= propsTypes
.end( ) )
1228 libcmis::PropertyTypePtr propType
= typeIt
->second
;
1229 libcmis::PropertyPtr
property( new libcmis::Property( propType
, values
) );
1230 m_pObjectProps
.insert( pair
< string
, libcmis::PropertyPtr
>( sName
, property
) );
1233 else if ( propIt
!= m_pObjectProps
.end( ) )
1235 propIt
->second
->setValues( values
);
1241 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */