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