LibreOffice Module ucb (master) 1
tdoc_provider.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
21/**************************************************************************
22 TODO
23 **************************************************************************
24
25 *************************************************************************/
26
28
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>
35#include <ucbhelper/macros.hxx>
36
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"
42
43using namespace com::sun::star;
44using namespace tdoc_ucp;
45
46
47// ContentProvider Implementation.
48
49
51 const uno::Reference< uno::XComponentContext >& rxContext )
52: ::ucbhelper::ContentProviderImplHelper( rxContext ),
53 m_xDocsMgr( new OfficeDocumentsManager( rxContext, this ) ),
54 m_xStgElemFac( new StorageElementFactory( rxContext, m_xDocsMgr ) )
55{
56}
57
58
59// virtual
60ContentProvider::~ContentProvider()
61{
62 if ( m_xDocsMgr.is() )
63 m_xDocsMgr->destroy();
64}
65
66
67// XInterface methods.
69 noexcept
70{
71 OWeakObject::acquire();
72}
73
75 noexcept
76{
77 OWeakObject::release();
78}
79
80css::uno::Any SAL_CALL ContentProvider::queryInterface( const css::uno::Type & rType )
81{
82 css::uno::Any aRet = cppu::queryInterface( rType,
83 static_cast< lang::XTypeProvider* >(this),
84 static_cast< lang::XServiceInfo* >(this),
85 static_cast< ucb::XContentProvider* >(this),
86 static_cast< frame::XTransientDocumentsDocumentContentIdentifierFactory* >(this),
87 static_cast< frame::XTransientDocumentsDocumentContentFactory* >(this)
88 );
89 return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
90}
91
92// XTypeProvider methods.
93
94
96 lang::XTypeProvider,
97 lang::XServiceInfo,
98 ucb::XContentProvider,
99 frame::XTransientDocumentsDocumentContentIdentifierFactory,
100 frame::XTransientDocumentsDocumentContentFactory );
101
102
103// XServiceInfo methods.
105{
106 return "com.sun.star.comp.ucb.TransientDocumentsContentProvider";
107}
108
109sal_Bool SAL_CALL ContentProvider::supportsService( const OUString& ServiceName )
110{
111 return cppu::supportsService( this, ServiceName );
112}
113
114css::uno::Sequence< OUString > SAL_CALL ContentProvider::getSupportedServiceNames()
115{
116 return { "com.sun.star.ucb.TransientDocumentsContentProvider" };
117}
118
119
120// Service factory implementation.
121
122
123extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
125 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
126{
127 return cppu::acquire(new ContentProvider(context));
128}
129
130// XContentProvider methods.
131
132
133// virtual
134uno::Reference< ucb::XContent > SAL_CALL
136 const uno::Reference< ucb::XContentIdentifier >& Identifier )
137{
138 Uri aUri( Identifier->getContentIdentifier() );
139 if ( !aUri.isValid() )
140 throw ucb::IllegalIdentifierException(
141 "Invalid URL!",
142 Identifier );
143
144 // Normalize URI.
145 uno::Reference< ucb::XContentIdentifier > xCanonicId
146 = new ::ucbhelper::ContentIdentifier( aUri.getUri() );
147
148 osl::MutexGuard aGuard( m_aMutex );
149
150 // Check, if a content with given id already exists...
151 uno::Reference< ucb::XContent > xContent
152 = queryExistingContent( xCanonicId );
153
154 if ( !xContent.is() )
155 {
156 // Create a new content.
157 xContent = Content::create( m_xContext, this, xCanonicId );
158 registerNewContent( xContent );
159 }
160
161 return xContent;
162}
163
164
165// XTransientDocumentsDocumentContentIdentifierFactory methods.
166
167uno::Reference<ucb::XContentIdentifier> SAL_CALL
169 uno::Reference<frame::XModel> const& xModel)
170{
171 // model -> id -> content identifier -> queryContent
172 if ( !m_xDocsMgr.is() )
173 {
174 throw lang::IllegalArgumentException(
175 "No Document Manager!",
176 static_cast< cppu::OWeakObject * >( this ),
177 1 );
178 }
179
181 if ( aDocId.isEmpty() )
182 {
183 throw lang::IllegalArgumentException(
184 "Unable to obtain document id from model!",
185 static_cast< cppu::OWeakObject * >( this ),
186 1 );
187 }
188
189 OUString aBuffer = TDOC_URL_SCHEME ":/" + aDocId;
190
191 uno::Reference< ucb::XContentIdentifier > xId
192 = new ::ucbhelper::ContentIdentifier( aBuffer );
193 return xId;
194}
195
196// XTransientDocumentsDocumentContentFactory methods.
197
198uno::Reference< ucb::XContent > SAL_CALL
200 uno::Reference<frame::XModel> const& xModel)
201{
202 uno::Reference<ucb::XContentIdentifier> const xId(
204
205 osl::MutexGuard aGuard( m_aMutex );
206
207 // Check, if a content with given id already exists...
208 uno::Reference< ucb::XContent > xContent
209 = queryExistingContent( xId );
210
211 if ( !xContent.is() )
212 {
213 // Create a new content.
214 xContent = Content::create( m_xContext, this, xId );
215 }
216
217 if ( xContent.is() )
218 return xContent;
219
220 // no content.
221 throw lang::IllegalArgumentException(
222 "Illegal Content Identifier!",
223 static_cast< cppu::OWeakObject * >( this ),
224 1 );
225}
226
227
228// interface OfficeDocumentsEventListener
229
230
231// virtual
232void ContentProvider::notifyDocumentClosed( std::u16string_view rDocId )
233{
234 osl::MutexGuard aGuard( getContentListMutex() );
235
236 ::ucbhelper::ContentRefList aAllContents;
237 queryExistingContents( aAllContents );
238
239 // Notify all content objects related to the closed doc.
240
241 bool bFoundDocumentContent = false;
243
244 for ( const auto& rContent : aAllContents )
245 {
246 Uri aUri( rContent->getIdentifier()->getContentIdentifier() );
247 OSL_ENSURE( aUri.isValid(),
248 "ContentProvider::notifyDocumentClosed - Invalid URI!" );
249
250 if ( !bFoundDocumentContent )
251 {
252 if ( aUri.isRoot() )
253 {
254 xRoot = static_cast< Content * >( rContent.get() );
255 }
256 else if ( aUri.isDocument() )
257 {
258 if ( aUri.getDocumentId() == rDocId )
259 {
260 bFoundDocumentContent = true;
261
262 // document content will notify removal of child itself;
263 // no need for the root to propagate this.
264 xRoot.clear();
265 }
266 }
267 }
268
269 if ( aUri.getDocumentId() == rDocId )
270 {
271 // Inform content.
273 = static_cast< Content * >( rContent.get() );
274
275 xContent->notifyDocumentClosed();
276 }
277 }
278
279 if ( xRoot.is() )
280 {
281 // No document content found for rDocId but root content
282 // instantiated. Root content must announce document removal
283 // to content event listeners.
284 xRoot->notifyChildRemoved( rDocId );
285 }
286}
287
288
289// virtual
290void ContentProvider::notifyDocumentOpened( std::u16string_view rDocId )
291{
292 osl::MutexGuard aGuard( getContentListMutex() );
293
294 ::ucbhelper::ContentRefList aAllContents;
295 queryExistingContents( aAllContents );
296
297 // Find root content. If instantiated let it propagate document insertion.
298
299 for ( const auto& rContent : aAllContents )
300 {
301 Uri aUri( rContent->getIdentifier()->getContentIdentifier() );
302 OSL_ENSURE( aUri.isValid(),
303 "ContentProvider::notifyDocumentOpened - Invalid URI!" );
304
305 if ( aUri.isRoot() )
306 {
308 = static_cast< Content * >( rContent.get() );
309 xRoot->notifyChildInserted( rDocId );
310
311 // Done.
312 break;
313 }
314 }
315}
316
317
318// Non-UNO
319
320
321uno::Reference< embed::XStorage >
322ContentProvider::queryStorage( const OUString & rUri,
323 StorageAccessMode eMode ) const
324{
325 if ( m_xStgElemFac.is() )
326 {
327 try
328 {
329 return m_xStgElemFac->createStorage( rUri, eMode );
330 }
331 catch ( embed::InvalidStorageException const & )
332 {
333 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
334 }
335 catch ( lang::IllegalArgumentException const & )
336 {
337 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
338 }
339 catch ( io::IOException const & )
340 {
341 // Okay to happen, for instance when the storage does not exist.
342 //OSL_ENSURE( false, "Caught IOException!" );
343 }
344 catch ( embed::StorageWrappedTargetException const & )
345 {
346 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
347 }
348 }
349 return uno::Reference< embed::XStorage >();
350}
351
352
353uno::Reference< embed::XStorage >
354ContentProvider::queryStorageClone( const OUString & rUri ) const
355{
356 if ( m_xStgElemFac.is() )
357 {
358 try
359 {
360 Uri aUri( rUri );
361 uno::Reference< embed::XStorage > xParentStorage
362 = m_xStgElemFac->createStorage( aUri.getParentUri(), READ );
363 uno::Reference< embed::XStorage > xStorage
364 = m_xStgElemFac->createTemporaryStorage();
365
366 xParentStorage->copyStorageElementLastCommitTo(
367 aUri.getDecodedName(), xStorage );
368 return xStorage;
369 }
370 catch ( embed::InvalidStorageException const & )
371 {
372 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
373 }
374 catch ( lang::IllegalArgumentException const & )
375 {
376 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
377 }
378 catch ( io::IOException const & )
379 {
380 // Okay to happen, for instance when the storage does not exist.
381 //OSL_ENSURE( false, "Caught IOException!" );
382 }
383 catch ( embed::StorageWrappedTargetException const & )
384 {
385 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
386 }
387 }
388
389 return uno::Reference< embed::XStorage >();
390}
391
392
393uno::Reference< io::XInputStream >
395 const OUString & rPassword ) const
396{
397 if ( m_xStgElemFac.is() )
398 {
399 try
400 {
401 return m_xStgElemFac->createInputStream( rUri, rPassword );
402 }
403 catch ( embed::InvalidStorageException const & )
404 {
405 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
406 }
407 catch ( lang::IllegalArgumentException const & )
408 {
409 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
410 }
411 catch ( io::IOException const & )
412 {
413 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
414 }
415 catch ( embed::StorageWrappedTargetException const & )
416 {
417 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
418 }
419// catch ( packages::WrongPasswordException const & )
420// {
421// // the key provided is wrong; rethrow; to be handled by caller.
422// throw;
423// }
424 }
425 return uno::Reference< io::XInputStream >();
426}
427
428
429uno::Reference< io::XOutputStream >
431 const OUString & rPassword,
432 bool bTruncate ) const
433{
434 if ( m_xStgElemFac.is() )
435 {
436 try
437 {
438 return
439 m_xStgElemFac->createOutputStream( rUri, rPassword, bTruncate );
440 }
441 catch ( embed::InvalidStorageException const & )
442 {
443 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
444 }
445 catch ( lang::IllegalArgumentException const & )
446 {
447 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
448 }
449 catch ( io::IOException const & )
450 {
451 // Okay to happen, for instance when the storage does not exist.
452 //OSL_ENSURE( false, "Caught IOException!" );
453 }
454 catch ( embed::StorageWrappedTargetException const & )
455 {
456 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
457 }
458// catch ( packages::WrongPasswordException const & )
459// {
460// // the key provided is wrong; rethrow; to be handled by caller.
461// throw;
462// }
463 }
464 return uno::Reference< io::XOutputStream >();
465}
466
467
468uno::Reference< io::XStream >
469ContentProvider::queryStream( const OUString & rUri,
470 const OUString & rPassword,
471 bool bTruncate ) const
472{
473 if ( m_xStgElemFac.is() )
474 {
475 try
476 {
477 return m_xStgElemFac->createStream( rUri, rPassword, bTruncate );
478 }
479 catch ( embed::InvalidStorageException const & )
480 {
481 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
482 }
483 catch ( lang::IllegalArgumentException const & )
484 {
485 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
486 }
487 catch ( io::IOException const & )
488 {
489 // Okay to happen, for instance when the storage does not exist.
490 //OSL_ENSURE( false, "Caught IOException!" );
491 }
492 catch ( embed::StorageWrappedTargetException const & )
493 {
494 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
495 }
496// catch ( packages::WrongPasswordException const & )
497// {
498// // the key provided is wrong; rethrow; to be handled by caller.
499// throw;
500// }
501 }
502 return uno::Reference< io::XStream >();
503}
504
505
507 const OUString & rUri, uno::Sequence< OUString > & rNames ) const
508{
509 Uri aUri( rUri );
510 if ( aUri.isRoot() )
511 {
512 // special handling for root, which has no storage, but children.
513 if ( m_xDocsMgr.is() )
514 {
515 rNames = m_xDocsMgr->queryDocuments();
516 return true;
517 }
518 }
519 else
520 {
521 if ( m_xStgElemFac.is() )
522 {
523 try
524 {
525 uno::Reference< embed::XStorage > xStorage
526 = m_xStgElemFac->createStorage( rUri, READ );
527
528 OSL_ENSURE( xStorage.is(), "Got no Storage!" );
529
530 if ( xStorage.is() )
531 {
532 rNames = xStorage->getElementNames();
533 return true;
534 }
535 }
536 catch ( embed::InvalidStorageException const & )
537 {
538 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
539 }
540 catch ( lang::IllegalArgumentException const & )
541 {
542 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
543 }
544 catch ( io::IOException const & )
545 {
546 // Okay to happen, for instance if the storage does not exist.
547 //OSL_ENSURE( false, "Caught IOException!" );
548 }
549 catch ( embed::StorageWrappedTargetException const & )
550 {
551 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
552 }
553 }
554 }
555 return false;
556}
557
558
559OUString
560ContentProvider::queryStorageTitle( const OUString & rUri ) const
561{
562 OUString aTitle;
563
564 Uri aUri( rUri );
565 if ( aUri.isRoot() )
566 {
567 // always empty.
568 aTitle.clear();
569 }
570 else if ( aUri.isDocument() )
571 {
572 // for documents, title shall not be derived from URL. It shall
573 // be something more 'speaking' than just the document UID.
574 if ( m_xDocsMgr.is() )
575 aTitle = m_xDocsMgr->queryStorageTitle( aUri.getDocumentId() );
576 }
577 else
578 {
579 // derive title from URL
580 aTitle = aUri.getDecodedName();
581 }
582
583 OSL_ENSURE( !aTitle.isEmpty() || aUri.isRoot(),
584 "ContentProvider::queryStorageTitle - empty title!" );
585 return aTitle;
586}
587
588
589uno::Reference< frame::XModel >
590ContentProvider::queryDocumentModel( const OUString & rUri ) const
591{
592 uno::Reference< frame::XModel > xModel;
593
594 if ( m_xDocsMgr.is() )
595 {
596 Uri aUri( rUri );
597 xModel = m_xDocsMgr->queryDocumentModel( aUri.getDocumentId() );
598 }
599
600 OSL_ENSURE( xModel.is(),
601 "ContentProvider::queryDocumentModel - no model!" );
602 return xModel;
603}
604
605/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void notifyDocumentOpened(std::u16string_view rDocId)
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
virtual void SAL_CALL release() noexcept override
void notifyDocumentClosed(std::u16string_view rDocId)
virtual OUString SAL_CALL getImplementationName() override
OUString queryStorageTitle(const OUString &rUri) const
css::uno::Reference< css::io::XOutputStream > queryOutputStream(const OUString &rUri, const OUString &rPassword, bool bTruncate) const
virtual css::uno::Reference< css::ucb::XContent > SAL_CALL createDocumentContent(const css::uno::Reference< css::frame::XModel > &Model) override
rtl::Reference< StorageElementFactory > m_xStgElemFac
css::uno::Reference< css::io::XInputStream > queryInputStream(const OUString &rUri, const OUString &rPassword) const
virtual css::uno::Reference< css::ucb::XContentIdentifier > SAL_CALL createDocumentContentIdentifier(css::uno::Reference< css::frame::XModel > const &xModel) override
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
css::uno::Reference< css::embed::XStorage > queryStorageClone(const OUString &rUri) const
rtl::Reference< OfficeDocumentsManager > m_xDocsMgr
virtual void SAL_CALL acquire() noexcept override
bool queryNamesOfChildren(const OUString &rUri, css::uno::Sequence< OUString > &rNames) const
css::uno::Reference< css::frame::XModel > queryDocumentModel(const OUString &rUri) const
virtual css::uno::Reference< css::ucb::XContent > SAL_CALL queryContent(const css::uno::Reference< css::ucb::XContentIdentifier > &Identifier) override
css::uno::Reference< css::io::XStream > queryStream(const OUString &rUri, const OUString &rPassword, bool bTruncate) const
css::uno::Reference< css::embed::XStorage > queryStorage(const OUString &rUri, StorageAccessMode eMode) const
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType) override
static rtl::Reference< Content > create(const css::uno::Reference< css::uno::XComponentContext > &rxContext, ContentProvider *pProvider, const css::uno::Reference< css::ucb::XContentIdentifier > &Identifier)
static OUString queryDocumentId(const css::uno::Reference< css::frame::XModel > &xModel)
bool isValid() const
Definition: tdoc_uri.hxx:57
bool isRoot() const
Definition: tdoc_uri.hxx:93
const OUString & getDecodedName() const
Definition: tdoc_uri.hxx:74
const OUString & getDocumentId() const
Definition: tdoc_uri.hxx:68
const OUString & getParentUri() const
Definition: tdoc_uri.hxx:65
bool isDocument() const
Definition: tdoc_uri.hxx:99
rtl::Reference< ContentImplHelper > queryExistingContent(const css::uno::Reference< css::ucb::XContentIdentifier > &Identifier)
void registerNewContent(const css::uno::Reference< css::ucb::XContent > &xContent)
void queryExistingContents(ContentRefList &rContents)
css::uno::Reference< css::uno::XComponentContext > m_xContext
#define TOOLS_WARN_EXCEPTION(area, stream)
Mode eMode
css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType, Interface1 *p1)
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
std::vector< ContentImplHelperRef > ContentRefList
friend ContentProvider
Definition: pkgprovider.cxx:54
Reference< XModel > xModel
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * ucb_tdoc_ContentProvider_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
XTYPEPROVIDER_IMPL_5(ContentProvider, lang::XTypeProvider, lang::XServiceInfo, ucb::XContentProvider, frame::XTransientDocumentsDocumentContentIdentifierFactory, frame::XTransientDocumentsDocumentContentFactory)
#define TDOC_URL_SCHEME
Definition: tdoc_uri.hxx:28
unsigned char sal_Bool
std::unique_ptr< char[]> aBuffer