Bump for 3.6-28
[LibreOffice.git] / ucb / source / ucp / cmis / cmis_content.cxx
blobcb4ff75c0ed99701b3da57c731abbf6881cfcf75
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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
13 * License.
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.
29 #include <cstdio>
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;
70 using namespace std;
72 namespace
74 class AuthProvider : public libcmis::AuthProvider
76 const com::sun::star::uno::Reference< com::sun::star::ucb::XCommandEnvironment>& m_xEnv;
77 rtl::OUString m_sUrl;
78 rtl::OUString m_sBindingUrl;
80 public:
81 AuthProvider ( const com::sun::star::uno::Reference<
82 com::sun::star::ucb::XCommandEnvironment>& xEnv,
83 rtl::OUString sUrl,
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 )
92 if ( m_xEnv.is() )
94 uno::Reference< task::XInteractionHandler > xIH
95 = m_xEnv->getInteractionHandler();
97 if ( xIH.is() )
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 );
115 if ( !xAbort.is() )
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() );
124 return true;
129 return false;
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;
148 return unoTime;
152 namespace cmis
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 ),
159 m_pSession( NULL ),
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,
184 sal_Bool bIsFolder )
185 throw ( ucb::ContentCreationException )
186 : ContentImplHelper( rxSMgr, pProvider, Identifier ),
187 m_pProvider( pProvider ),
188 m_pSession( NULL ),
189 m_bTransient( true )
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 );
215 Content::~Content()
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 ) );
227 else
229 m_pObject = m_pSession->getRootFolder( );
230 m_sObjectPath = "/";
231 m_sObjectId = rtl::OUString( );
235 return m_pObject;
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 ),
258 xEnv,
259 rtl::OUString::createFromAscii( e.what() ) );
261 return bIsFolder;
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 );
279 sal_Int32 nProps;
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" );
301 else
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" );
315 else
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( '/' );
351 if ( nPos >= 0 )
352 sTitle = sPath.copy( nPos + 1 );
355 if ( !sTitle.isEmpty( ) )
356 xRow->appendString( rProp, sTitle );
357 else
358 xRow->appendVoid( rProp );
360 else if ( rProp.Name == "TitleOnServer" )
362 string path;
365 vector< string > paths = getObject( )->getPaths( );
366 if ( paths.size( ) > 0 )
367 path = paths.front( );
368 else
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() );
404 else
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() ) );
423 else
424 xRow->appendVoid( rProp );
426 catch ( const libcmis::Exception& )
428 xRow->appendVoid( rProp );
431 else
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( )
445 bool bExists = true;
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& )
456 bExists = false;
459 return bExists;
462 void Content::queryChildren( ContentRefList& /*rChildren*/ )
464 SAL_INFO( "cmisucp", "TODO - Content::queryChildren()" );
465 // TODO Implement me
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
475 if ( !exists( ) )
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);
488 uno::Any aRet;
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 );
500 aRet <<= xSet;
502 else if ( rOpenCommand.Sink.is() )
504 if (
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 ) ) ),
513 xEnv );
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 ) ),
527 xEnv );
530 else
531 SAL_INFO( "cmisucp", "Open falling through ..." );
533 return aRet;
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(
548 uno::makeAny(
549 ucb::InteractiveBadTransferURLException(
550 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
551 "Unsupported URL scheme!" )),
552 static_cast< cppu::OWeakObject * >( this ) ) ),
553 xEnv );
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 ) ) ),
569 xEnv );
572 // For transient content, the URL is the one of the parent
573 if ( m_bTransient )
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 ) ) ),
595 xEnv );
597 string newName = it->second->getStrings( ).front( );
598 string newPath = pFolder->getPath( );
599 if ( newPath[ newPath.size( ) - 1 ] != '/' )
600 newPath += "/";
601 newPath += newName;
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 ) ) ),
622 xEnv );
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 );
636 else
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( ) );
642 if ( bIsFolder )
644 libcmis::FolderPtr pNew = pFolder->createFolder( m_pObjectProps );
645 sNewPath = STD_TO_OUSTR( newPath );
647 else
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;
661 URL aUrl( m_sURL );
662 aUrl.setObjectPath( m_sObjectPath );
663 m_sURL = aUrl.asString( );
664 m_pObject.reset( );
665 m_pObjectType.reset( );
666 m_pObjectProps.clear( );
667 m_bTransient = false;
669 inserted();
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 );
686 xOut->closeOutput();
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 ),
708 xEnv,
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 ) );
729 aRet[ n ] <<= e;
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 ) );
739 continue;
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 );
747 continue;
751 setCmisProperty( "cmis:name", OUSTR_TO_STDSTR( aNewTitle ) );
752 bChanged = true;
754 else
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 ) );
759 aRet[ n ] <<= e;
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 ),
776 xEnv,
777 rtl::OUString::createFromAscii( e.what() ) );
780 return aRet;
783 sal_Bool Content::feedSink( uno::Reference< uno::XInterface> xSink,
784 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
786 if ( !xSink.is() )
787 return sal_False;
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() ) )
794 return sal_False;
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 );
805 if( !xIn.is( ) )
806 return sal_False;
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 ),
819 xEnv,
820 rtl::OUString::createFromAscii( e.what() ) );
823 return sal_True;
826 sal_Bool Content::exchangeIdentity( const uno::Reference< ucb::XContentIdentifier >& /*xNewId*/ )
828 sal_Bool bRet = sal_False;
829 SAL_INFO( "cmisucp", "TODO - Content::exchangeIdentity()" );
830 // TODO Implement me
832 return bRet;
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[] =
885 // Required commands
886 ucb::CommandInfo
887 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getCommandInfo" ) ),
888 -1, getCppuVoidType() ),
889 ucb::CommandInfo
890 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getPropertySetInfo" ) ),
891 -1, getCppuVoidType() ),
892 ucb::CommandInfo
893 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getPropertyValues" ) ),
894 -1, getCppuType( static_cast<uno::Sequence< beans::Property > * >( 0 ) ) ),
895 ucb::CommandInfo
896 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "setPropertyValues" ) ),
897 -1, getCppuType( static_cast<uno::Sequence< beans::PropertyValue > * >( 0 ) ) ),
899 // Optional standard commands
900 ucb::CommandInfo
901 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "delete" ) ),
902 -1, getCppuBooleanType() ),
903 ucb::CommandInfo
904 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "insert" ) ),
905 -1, getCppuType( static_cast<ucb::InsertCommandArgument * >( 0 ) ) ),
906 ucb::CommandInfo
907 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "open" ) ),
908 -1, getCppuType( static_cast<ucb::OpenCommandArgument2 * >( 0 ) ) ),
910 // Folder Only, omitted if not a folder
911 ucb::CommandInfo
912 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "transfer" ) ),
913 -1, getCppuType( static_cast<ucb::TransferInfo * >( 0 ) ) ),
914 ucb::CommandInfo
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( )
925 rtl::OUString sRet;
927 SAL_INFO( "cmisucp", "Content::getParentURL()" );
929 string parentPath;
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( );
940 else
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
950 // get the parents
953 if ( !parentPath.empty() )
955 URL aUrl( m_sURL );
956 aUrl.setObjectPath( STD_TO_OUSTR( parentPath ) );
957 sRet = aUrl.asString( );
960 return sRet;
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"));
991 return aSNS;
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 );
1010 uno::Any aRet;
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( );
1067 else
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 ),
1079 xEnv,
1080 rtl::OUString::createFromAscii( e.what() ) );
1083 else
1085 SAL_INFO( "cmisucp", "Unknown command to execute" );
1087 ucbhelper::cancelCommandExecution
1088 ( uno::makeAny( ucb::UnsupportedCommandException
1089 ( rtl::OUString(),
1090 static_cast< cppu::OWeakObject * >( this ) ) ),
1091 xEnv );
1094 return aRet;
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;
1118 else
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();
1158 else
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 );
1194 // file
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;
1200 // folder
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;
1205 return seq;
1207 else
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: */