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