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