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