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: ContentProvider_Base( 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// XServiceInfo methods.
69{
70 return "com.sun.star.comp.ucb.TransientDocumentsContentProvider";
71}
72
73sal_Bool SAL_CALL ContentProvider::supportsService( const OUString& ServiceName )
74{
75 return cppu::supportsService( this, ServiceName );
76}
77
78css::uno::Sequence< OUString > SAL_CALL ContentProvider::getSupportedServiceNames()
79{
80 return { "com.sun.star.ucb.TransientDocumentsContentProvider" };
81}
82
83
84// Service factory implementation.
85
86
87extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
89 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
90{
91 return cppu::acquire(new ContentProvider(context));
92}
93
94// XContentProvider methods.
95
96
97// virtual
98uno::Reference< ucb::XContent > SAL_CALL
100 const uno::Reference< ucb::XContentIdentifier >& Identifier )
101{
102 Uri aUri( Identifier->getContentIdentifier() );
103 if ( !aUri.isValid() )
104 throw ucb::IllegalIdentifierException(
105 "Invalid URL!",
106 Identifier );
107
108 // Normalize URI.
109 uno::Reference< ucb::XContentIdentifier > xCanonicId
110 = new ::ucbhelper::ContentIdentifier( aUri.getUri() );
111
112 osl::MutexGuard aGuard( m_aMutex );
113
114 // Check, if a content with given id already exists...
115 uno::Reference< ucb::XContent > xContent
116 = queryExistingContent( xCanonicId );
117
118 if ( !xContent.is() )
119 {
120 // Create a new content.
121 xContent = Content::create( m_xContext, this, xCanonicId );
122 registerNewContent( xContent );
123 }
124
125 return xContent;
126}
127
128
129// XTransientDocumentsDocumentContentIdentifierFactory methods.
130
131uno::Reference<ucb::XContentIdentifier> SAL_CALL
133 uno::Reference<frame::XModel> const& xModel)
134{
135 // model -> id -> content identifier -> queryContent
136 if ( !m_xDocsMgr.is() )
137 {
138 throw lang::IllegalArgumentException(
139 "No Document Manager!",
140 getXWeak(),
141 1 );
142 }
143
145 if ( aDocId.isEmpty() )
146 {
147 throw lang::IllegalArgumentException(
148 "Unable to obtain document id from model!",
149 getXWeak(),
150 1 );
151 }
152
153 OUString aBuffer = TDOC_URL_SCHEME ":/" + aDocId;
154
155 uno::Reference< ucb::XContentIdentifier > xId
156 = new ::ucbhelper::ContentIdentifier( aBuffer );
157 return xId;
158}
159
160// XTransientDocumentsDocumentContentFactory methods.
161
162uno::Reference< ucb::XContent > SAL_CALL
164 uno::Reference<frame::XModel> const& xModel)
165{
166 uno::Reference<ucb::XContentIdentifier> const xId(
168
169 osl::MutexGuard aGuard( m_aMutex );
170
171 // Check, if a content with given id already exists...
172 uno::Reference< ucb::XContent > xContent
173 = queryExistingContent( xId );
174
175 if ( !xContent.is() )
176 {
177 // Create a new content.
178 xContent = Content::create( m_xContext, this, xId );
179 }
180
181 if ( xContent.is() )
182 return xContent;
183
184 // no content.
185 throw lang::IllegalArgumentException(
186 "Illegal Content Identifier!",
187 getXWeak(),
188 1 );
189}
190
191
192// interface OfficeDocumentsEventListener
193
194
195// virtual
196void ContentProvider::notifyDocumentClosed( std::u16string_view rDocId )
197{
198 osl::MutexGuard aGuard( getContentListMutex() );
199
200 ::ucbhelper::ContentRefList aAllContents;
201 queryExistingContents( aAllContents );
202
203 // Notify all content objects related to the closed doc.
204
205 bool bFoundDocumentContent = false;
207
208 for ( const auto& rContent : aAllContents )
209 {
210 Uri aUri( rContent->getIdentifier()->getContentIdentifier() );
211 OSL_ENSURE( aUri.isValid(),
212 "ContentProvider::notifyDocumentClosed - Invalid URI!" );
213
214 if ( !bFoundDocumentContent )
215 {
216 if ( aUri.isRoot() )
217 {
218 xRoot = static_cast< Content * >( rContent.get() );
219 }
220 else if ( aUri.isDocument() )
221 {
222 if ( aUri.getDocumentId() == rDocId )
223 {
224 bFoundDocumentContent = true;
225
226 // document content will notify removal of child itself;
227 // no need for the root to propagate this.
228 xRoot.clear();
229 }
230 }
231 }
232
233 if ( aUri.getDocumentId() == rDocId )
234 {
235 // Inform content.
237 = static_cast< Content * >( rContent.get() );
238
239 xContent->notifyDocumentClosed();
240 }
241 }
242
243 if ( xRoot.is() )
244 {
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 );
249 }
250}
251
252
253// virtual
254void ContentProvider::notifyDocumentOpened( std::u16string_view rDocId )
255{
256 osl::MutexGuard aGuard( getContentListMutex() );
257
258 ::ucbhelper::ContentRefList aAllContents;
259 queryExistingContents( aAllContents );
260
261 // Find root content. If instantiated let it propagate document insertion.
262
263 for ( const auto& rContent : aAllContents )
264 {
265 Uri aUri( rContent->getIdentifier()->getContentIdentifier() );
266 OSL_ENSURE( aUri.isValid(),
267 "ContentProvider::notifyDocumentOpened - Invalid URI!" );
268
269 if ( aUri.isRoot() )
270 {
272 = static_cast< Content * >( rContent.get() );
273 xRoot->notifyChildInserted( rDocId );
274
275 // Done.
276 break;
277 }
278 }
279}
280
281
282// Non-UNO
283
284
285uno::Reference< embed::XStorage >
286ContentProvider::queryStorage( const OUString & rUri,
287 StorageAccessMode eMode ) const
288{
289 if ( m_xStgElemFac.is() )
290 {
291 try
292 {
293 return m_xStgElemFac->createStorage( rUri, eMode );
294 }
295 catch ( embed::InvalidStorageException const & )
296 {
297 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
298 }
299 catch ( lang::IllegalArgumentException const & )
300 {
301 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
302 }
303 catch ( io::IOException const & )
304 {
305 // Okay to happen, for instance when the storage does not exist.
306 //OSL_ENSURE( false, "Caught IOException!" );
307 }
308 catch ( embed::StorageWrappedTargetException const & )
309 {
310 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
311 }
312 }
313 return uno::Reference< embed::XStorage >();
314}
315
316
317uno::Reference< embed::XStorage >
318ContentProvider::queryStorageClone( const OUString & rUri ) const
319{
320 if ( m_xStgElemFac.is() )
321 {
322 try
323 {
324 Uri aUri( rUri );
325 uno::Reference< embed::XStorage > xParentStorage
326 = m_xStgElemFac->createStorage( aUri.getParentUri(), READ );
327 uno::Reference< embed::XStorage > xStorage
328 = m_xStgElemFac->createTemporaryStorage();
329
330 xParentStorage->copyStorageElementLastCommitTo(
331 aUri.getDecodedName(), xStorage );
332 return xStorage;
333 }
334 catch ( embed::InvalidStorageException const & )
335 {
336 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
337 }
338 catch ( lang::IllegalArgumentException const & )
339 {
340 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
341 }
342 catch ( io::IOException const & )
343 {
344 // Okay to happen, for instance when the storage does not exist.
345 //OSL_ENSURE( false, "Caught IOException!" );
346 }
347 catch ( embed::StorageWrappedTargetException const & )
348 {
349 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
350 }
351 }
352
353 return uno::Reference< embed::XStorage >();
354}
355
356
357uno::Reference< io::XInputStream >
359 const OUString & rPassword ) const
360{
361 if ( m_xStgElemFac.is() )
362 {
363 try
364 {
365 return m_xStgElemFac->createInputStream( rUri, rPassword );
366 }
367 catch ( embed::InvalidStorageException const & )
368 {
369 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
370 }
371 catch ( lang::IllegalArgumentException const & )
372 {
373 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
374 }
375 catch ( io::IOException const & )
376 {
377 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
378 }
379 catch ( embed::StorageWrappedTargetException const & )
380 {
381 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
382 }
383// catch ( packages::WrongPasswordException const & )
384// {
385// // the key provided is wrong; rethrow; to be handled by caller.
386// throw;
387// }
388 }
389 return uno::Reference< io::XInputStream >();
390}
391
392
393uno::Reference< io::XOutputStream >
395 const OUString & rPassword,
396 bool bTruncate ) const
397{
398 if ( m_xStgElemFac.is() )
399 {
400 try
401 {
402 return
403 m_xStgElemFac->createOutputStream( rUri, rPassword, bTruncate );
404 }
405 catch ( embed::InvalidStorageException const & )
406 {
407 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
408 }
409 catch ( lang::IllegalArgumentException const & )
410 {
411 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
412 }
413 catch ( io::IOException const & )
414 {
415 // Okay to happen, for instance when the storage does not exist.
416 //OSL_ENSURE( false, "Caught IOException!" );
417 }
418 catch ( embed::StorageWrappedTargetException const & )
419 {
420 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
421 }
422// catch ( packages::WrongPasswordException const & )
423// {
424// // the key provided is wrong; rethrow; to be handled by caller.
425// throw;
426// }
427 }
428 return uno::Reference< io::XOutputStream >();
429}
430
431
432uno::Reference< io::XStream >
433ContentProvider::queryStream( const OUString & rUri,
434 const OUString & rPassword,
435 bool bTruncate ) const
436{
437 if ( m_xStgElemFac.is() )
438 {
439 try
440 {
441 return m_xStgElemFac->createStream( rUri, rPassword, bTruncate );
442 }
443 catch ( embed::InvalidStorageException const & )
444 {
445 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
446 }
447 catch ( lang::IllegalArgumentException const & )
448 {
449 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
450 }
451 catch ( io::IOException const & )
452 {
453 // Okay to happen, for instance when the storage does not exist.
454 //OSL_ENSURE( false, "Caught IOException!" );
455 }
456 catch ( embed::StorageWrappedTargetException const & )
457 {
458 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
459 }
460// catch ( packages::WrongPasswordException const & )
461// {
462// // the key provided is wrong; rethrow; to be handled by caller.
463// throw;
464// }
465 }
466 return uno::Reference< io::XStream >();
467}
468
469
471 const OUString & rUri, uno::Sequence< OUString > & rNames ) const
472{
473 Uri aUri( rUri );
474 if ( aUri.isRoot() )
475 {
476 // special handling for root, which has no storage, but children.
477 if ( m_xDocsMgr.is() )
478 {
479 rNames = m_xDocsMgr->queryDocuments();
480 return true;
481 }
482 }
483 else
484 {
485 if ( m_xStgElemFac.is() )
486 {
487 try
488 {
489 uno::Reference< embed::XStorage > xStorage
490 = m_xStgElemFac->createStorage( rUri, READ );
491
492 OSL_ENSURE( xStorage.is(), "Got no Storage!" );
493
494 if ( xStorage.is() )
495 {
496 rNames = xStorage->getElementNames();
497 return true;
498 }
499 }
500 catch ( embed::InvalidStorageException const & )
501 {
502 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
503 }
504 catch ( lang::IllegalArgumentException const & )
505 {
506 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
507 }
508 catch ( io::IOException const & )
509 {
510 // Okay to happen, for instance if the storage does not exist.
511 //OSL_ENSURE( false, "Caught IOException!" );
512 }
513 catch ( embed::StorageWrappedTargetException const & )
514 {
515 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
516 }
517 }
518 }
519 return false;
520}
521
522
523OUString
524ContentProvider::queryStorageTitle( const OUString & rUri ) const
525{
526 OUString aTitle;
527
528 Uri aUri( rUri );
529 if ( aUri.isRoot() )
530 {
531 // always empty.
532 aTitle.clear();
533 }
534 else if ( aUri.isDocument() )
535 {
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() );
540 }
541 else
542 {
543 // derive title from URL
544 aTitle = aUri.getDecodedName();
545 }
546
547 OSL_ENSURE( !aTitle.isEmpty() || aUri.isRoot(),
548 "ContentProvider::queryStorageTitle - empty title!" );
549 return aTitle;
550}
551
552
553uno::Reference< frame::XModel >
554ContentProvider::queryDocumentModel( const OUString & rUri ) const
555{
556 uno::Reference< frame::XModel > xModel;
557
558 if ( m_xDocsMgr.is() )
559 {
560 Uri aUri( rUri );
561 xModel = m_xDocsMgr->queryDocumentModel( aUri.getDocumentId() );
562 }
563
564 OSL_ENSURE( xModel.is(),
565 "ContentProvider::queryDocumentModel - no model!" );
566 return xModel;
567}
568
569
570css::util::DateTime ContentProvider::queryStreamDateModified(OUString const & uri) const {
571 return m_xDocsMgr->queryStreamDateModified(uri);
572}
573
574/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XComponentContext > m_xContext
void notifyDocumentOpened(std::u16string_view rDocId)
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
css::util::DateTime queryStreamDateModified(OUString const &uri) const
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
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
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
#define TOOLS_WARN_EXCEPTION(area, stream)
std::mutex m_aMutex
Mode eMode
cppu::ImplInheritanceHelper< ::ucbhelper::ContentProviderImplHelper, css::container::XContainerListener, css::lang::XComponent > ContentProvider_Base
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 &)
#define TDOC_URL_SCHEME
Definition: tdoc_uri.hxx:28
unsigned char sal_Bool
std::unique_ptr< char[]> aBuffer