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