1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 /**************************************************************************
23 **************************************************************************
25 *************************************************************************/
27 #include <comphelper/diagnose_ex.hxx>
29 #include <com/sun/star/embed/InvalidStorageException.hpp>
30 #include <com/sun/star/embed/StorageWrappedTargetException.hpp>
31 #include <com/sun/star/io/IOException.hpp>
32 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
33 #include <cppuhelper/queryinterface.hxx>
34 #include <ucbhelper/contentidentifier.hxx>
35 #include <ucbhelper/macros.hxx>
37 #include "tdoc_provider.hxx"
38 #include "tdoc_content.hxx"
39 #include "tdoc_uri.hxx"
40 #include "tdoc_docmgr.hxx"
41 #include "tdoc_storage.hxx"
43 using namespace com::sun::star
;
44 using namespace tdoc_ucp
;
47 // ContentProvider Implementation.
50 ContentProvider::ContentProvider(
51 const uno::Reference
< uno::XComponentContext
>& rxContext
)
52 : ContentProvider_Base( rxContext
),
53 m_xDocsMgr( new OfficeDocumentsManager( rxContext
, this ) ),
54 m_xStgElemFac( new StorageElementFactory( rxContext
, m_xDocsMgr
) )
60 ContentProvider::~ContentProvider()
62 if ( m_xDocsMgr
.is() )
63 m_xDocsMgr
->destroy();
67 // XServiceInfo methods.
68 OUString SAL_CALL
ContentProvider::getImplementationName()
70 return "com.sun.star.comp.ucb.TransientDocumentsContentProvider";
73 sal_Bool SAL_CALL
ContentProvider::supportsService( const OUString
& ServiceName
)
75 return cppu::supportsService( this, ServiceName
);
78 css::uno::Sequence
< OUString
> SAL_CALL
ContentProvider::getSupportedServiceNames()
80 return { "com.sun.star.ucb.TransientDocumentsContentProvider" };
84 // Service factory implementation.
87 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
88 ucb_tdoc_ContentProvider_get_implementation(
89 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
91 return cppu::acquire(new ContentProvider(context
));
94 // XContentProvider methods.
98 uno::Reference
< ucb::XContent
> SAL_CALL
99 ContentProvider::queryContent(
100 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
)
102 Uri
aUri( Identifier
->getContentIdentifier() );
103 if ( !aUri
.isValid() )
104 throw ucb::IllegalIdentifierException(
109 uno::Reference
< ucb::XContentIdentifier
> xCanonicId
110 = new ::ucbhelper::ContentIdentifier( aUri
.getUri() );
112 osl::MutexGuard
aGuard( m_aMutex
);
114 // Check, if a content with given id already exists...
115 uno::Reference
< ucb::XContent
> xContent
116 = queryExistingContent( xCanonicId
);
118 if ( !xContent
.is() )
120 // Create a new content.
121 xContent
= Content::create( m_xContext
, this, xCanonicId
);
122 registerNewContent( xContent
);
129 // XTransientDocumentsDocumentContentIdentifierFactory methods.
131 uno::Reference
<ucb::XContentIdentifier
> SAL_CALL
132 ContentProvider::createDocumentContentIdentifier(
133 uno::Reference
<frame::XModel
> const& xModel
)
135 // model -> id -> content identifier -> queryContent
136 if ( !m_xDocsMgr
.is() )
138 throw lang::IllegalArgumentException(
139 "No Document Manager!",
140 static_cast< cppu::OWeakObject
* >( this ),
144 OUString aDocId
= tdoc_ucp::OfficeDocumentsManager::queryDocumentId(xModel
);
145 if ( aDocId
.isEmpty() )
147 throw lang::IllegalArgumentException(
148 "Unable to obtain document id from model!",
149 static_cast< cppu::OWeakObject
* >( this ),
153 OUString aBuffer
= TDOC_URL_SCHEME
":/" + aDocId
;
155 uno::Reference
< ucb::XContentIdentifier
> xId
156 = new ::ucbhelper::ContentIdentifier( aBuffer
);
160 // XTransientDocumentsDocumentContentFactory methods.
162 uno::Reference
< ucb::XContent
> SAL_CALL
163 ContentProvider::createDocumentContent(
164 uno::Reference
<frame::XModel
> const& xModel
)
166 uno::Reference
<ucb::XContentIdentifier
> const xId(
167 createDocumentContentIdentifier(xModel
));
169 osl::MutexGuard
aGuard( m_aMutex
);
171 // Check, if a content with given id already exists...
172 uno::Reference
< ucb::XContent
> xContent
173 = queryExistingContent( xId
);
175 if ( !xContent
.is() )
177 // Create a new content.
178 xContent
= Content::create( m_xContext
, this, xId
);
185 throw lang::IllegalArgumentException(
186 "Illegal Content Identifier!",
187 static_cast< cppu::OWeakObject
* >( this ),
192 // interface OfficeDocumentsEventListener
196 void ContentProvider::notifyDocumentClosed( std::u16string_view rDocId
)
198 osl::MutexGuard
aGuard( getContentListMutex() );
200 ::ucbhelper::ContentRefList aAllContents
;
201 queryExistingContents( aAllContents
);
203 // Notify all content objects related to the closed doc.
205 bool bFoundDocumentContent
= false;
206 rtl::Reference
< Content
> xRoot
;
208 for ( const auto& rContent
: aAllContents
)
210 Uri
aUri( rContent
->getIdentifier()->getContentIdentifier() );
211 OSL_ENSURE( aUri
.isValid(),
212 "ContentProvider::notifyDocumentClosed - Invalid URI!" );
214 if ( !bFoundDocumentContent
)
218 xRoot
= static_cast< Content
* >( rContent
.get() );
220 else if ( aUri
.isDocument() )
222 if ( aUri
.getDocumentId() == rDocId
)
224 bFoundDocumentContent
= true;
226 // document content will notify removal of child itself;
227 // no need for the root to propagate this.
233 if ( aUri
.getDocumentId() == rDocId
)
236 rtl::Reference
< Content
> xContent
237 = static_cast< Content
* >( rContent
.get() );
239 xContent
->notifyDocumentClosed();
245 // No document content found for rDocId but root content
246 // instantiated. Root content must announce document removal
247 // to content event listeners.
248 xRoot
->notifyChildRemoved( rDocId
);
254 void ContentProvider::notifyDocumentOpened( std::u16string_view rDocId
)
256 osl::MutexGuard
aGuard( getContentListMutex() );
258 ::ucbhelper::ContentRefList aAllContents
;
259 queryExistingContents( aAllContents
);
261 // Find root content. If instantiated let it propagate document insertion.
263 for ( const auto& rContent
: aAllContents
)
265 Uri
aUri( rContent
->getIdentifier()->getContentIdentifier() );
266 OSL_ENSURE( aUri
.isValid(),
267 "ContentProvider::notifyDocumentOpened - Invalid URI!" );
271 rtl::Reference
< Content
> xRoot
272 = static_cast< Content
* >( rContent
.get() );
273 xRoot
->notifyChildInserted( rDocId
);
285 uno::Reference
< embed::XStorage
>
286 ContentProvider::queryStorage( const OUString
& rUri
,
287 StorageAccessMode eMode
) const
289 if ( m_xStgElemFac
.is() )
293 return m_xStgElemFac
->createStorage( rUri
, eMode
);
295 catch ( embed::InvalidStorageException
const & )
297 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
299 catch ( lang::IllegalArgumentException
const & )
301 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
303 catch ( io::IOException
const & )
305 // Okay to happen, for instance when the storage does not exist.
306 //OSL_ENSURE( false, "Caught IOException!" );
308 catch ( embed::StorageWrappedTargetException
const & )
310 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
313 return uno::Reference
< embed::XStorage
>();
317 uno::Reference
< embed::XStorage
>
318 ContentProvider::queryStorageClone( const OUString
& rUri
) const
320 if ( m_xStgElemFac
.is() )
325 uno::Reference
< embed::XStorage
> xParentStorage
326 = m_xStgElemFac
->createStorage( aUri
.getParentUri(), READ
);
327 uno::Reference
< embed::XStorage
> xStorage
328 = m_xStgElemFac
->createTemporaryStorage();
330 xParentStorage
->copyStorageElementLastCommitTo(
331 aUri
.getDecodedName(), xStorage
);
334 catch ( embed::InvalidStorageException
const & )
336 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
338 catch ( lang::IllegalArgumentException
const & )
340 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
342 catch ( io::IOException
const & )
344 // Okay to happen, for instance when the storage does not exist.
345 //OSL_ENSURE( false, "Caught IOException!" );
347 catch ( embed::StorageWrappedTargetException
const & )
349 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
353 return uno::Reference
< embed::XStorage
>();
357 uno::Reference
< io::XInputStream
>
358 ContentProvider::queryInputStream( const OUString
& rUri
,
359 const OUString
& rPassword
) const
361 if ( m_xStgElemFac
.is() )
365 return m_xStgElemFac
->createInputStream( rUri
, rPassword
);
367 catch ( embed::InvalidStorageException
const & )
369 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
371 catch ( lang::IllegalArgumentException
const & )
373 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
375 catch ( io::IOException
const & )
377 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
379 catch ( embed::StorageWrappedTargetException
const & )
381 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
383 // catch ( packages::WrongPasswordException const & )
385 // // the key provided is wrong; rethrow; to be handled by caller.
389 return uno::Reference
< io::XInputStream
>();
393 uno::Reference
< io::XOutputStream
>
394 ContentProvider::queryOutputStream( const OUString
& rUri
,
395 const OUString
& rPassword
,
396 bool bTruncate
) const
398 if ( m_xStgElemFac
.is() )
403 m_xStgElemFac
->createOutputStream( rUri
, rPassword
, bTruncate
);
405 catch ( embed::InvalidStorageException
const & )
407 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
409 catch ( lang::IllegalArgumentException
const & )
411 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
413 catch ( io::IOException
const & )
415 // Okay to happen, for instance when the storage does not exist.
416 //OSL_ENSURE( false, "Caught IOException!" );
418 catch ( embed::StorageWrappedTargetException
const & )
420 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
422 // catch ( packages::WrongPasswordException const & )
424 // // the key provided is wrong; rethrow; to be handled by caller.
428 return uno::Reference
< io::XOutputStream
>();
432 uno::Reference
< io::XStream
>
433 ContentProvider::queryStream( const OUString
& rUri
,
434 const OUString
& rPassword
,
435 bool bTruncate
) const
437 if ( m_xStgElemFac
.is() )
441 return m_xStgElemFac
->createStream( rUri
, rPassword
, bTruncate
);
443 catch ( embed::InvalidStorageException
const & )
445 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
447 catch ( lang::IllegalArgumentException
const & )
449 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
451 catch ( io::IOException
const & )
453 // Okay to happen, for instance when the storage does not exist.
454 //OSL_ENSURE( false, "Caught IOException!" );
456 catch ( embed::StorageWrappedTargetException
const & )
458 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
460 // catch ( packages::WrongPasswordException const & )
462 // // the key provided is wrong; rethrow; to be handled by caller.
466 return uno::Reference
< io::XStream
>();
470 bool ContentProvider::queryNamesOfChildren(
471 const OUString
& rUri
, uno::Sequence
< OUString
> & rNames
) const
476 // special handling for root, which has no storage, but children.
477 if ( m_xDocsMgr
.is() )
479 rNames
= m_xDocsMgr
->queryDocuments();
485 if ( m_xStgElemFac
.is() )
489 uno::Reference
< embed::XStorage
> xStorage
490 = m_xStgElemFac
->createStorage( rUri
, READ
);
492 OSL_ENSURE( xStorage
.is(), "Got no Storage!" );
496 rNames
= xStorage
->getElementNames();
500 catch ( embed::InvalidStorageException
const & )
502 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
504 catch ( lang::IllegalArgumentException
const & )
506 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
508 catch ( io::IOException
const & )
510 // Okay to happen, for instance if the storage does not exist.
511 //OSL_ENSURE( false, "Caught IOException!" );
513 catch ( embed::StorageWrappedTargetException
const & )
515 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
524 ContentProvider::queryStorageTitle( const OUString
& rUri
) const
534 else if ( aUri
.isDocument() )
536 // for documents, title shall not be derived from URL. It shall
537 // be something more 'speaking' than just the document UID.
538 if ( m_xDocsMgr
.is() )
539 aTitle
= m_xDocsMgr
->queryStorageTitle( aUri
.getDocumentId() );
543 // derive title from URL
544 aTitle
= aUri
.getDecodedName();
547 OSL_ENSURE( !aTitle
.isEmpty() || aUri
.isRoot(),
548 "ContentProvider::queryStorageTitle - empty title!" );
553 uno::Reference
< frame::XModel
>
554 ContentProvider::queryDocumentModel( const OUString
& rUri
) const
556 uno::Reference
< frame::XModel
> xModel
;
558 if ( m_xDocsMgr
.is() )
561 xModel
= m_xDocsMgr
->queryDocumentModel( aUri
.getDocumentId() );
564 OSL_ENSURE( xModel
.is(),
565 "ContentProvider::queryDocumentModel - no model!" );
570 css::util::DateTime
ContentProvider::queryStreamDateModified(OUString
const & uri
) const {
571 return m_xDocsMgr
->queryStreamDateModified(uri
);
574 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */