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 7 : ContentProvider::ContentProvider(
53 : const uno::Reference< uno::XComponentContext >& rxContext )
54 : : ::ucbhelper::ContentProviderImplHelper( rxContext ),
55 7 : m_xDocsMgr( new OfficeDocumentsManager( rxContext, this ) ),
56 14 : m_xStgElemFac( new StorageElementFactory( rxContext, m_xDocsMgr ) )
57 : {
58 7 : }
59 :
60 : //=========================================================================
61 : // virtual
62 21 : ContentProvider::~ContentProvider()
63 : {
64 7 : if ( m_xDocsMgr.is() )
65 7 : m_xDocsMgr->destroy();
66 14 : }
67 :
68 : //=========================================================================
69 : //
70 : // XInterface methods.
71 : //
72 : //=========================================================================
73 :
74 1425 : 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 29 : 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 7 : TDOC_CONTENT_PROVIDER_SERVICE_NAME ) ) );
104 :
105 : //=========================================================================
106 : //
107 : // Service factory implementation.
108 : //
109 : //=========================================================================
110 :
111 7 : 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 3 : ContentProvider::queryContent(
122 : const uno::Reference< ucb::XContentIdentifier >& Identifier )
123 : throw( ucb::IllegalIdentifierException, uno::RuntimeException )
124 : {
125 3 : Uri aUri( Identifier->getContentIdentifier() );
126 3 : 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 3 : = new ::ucbhelper::ContentIdentifier( aUri.getUri() );
134 :
135 3 : osl::MutexGuard aGuard( m_aMutex );
136 :
137 : // Check, if a content with given id already exists...
138 : uno::Reference< ucb::XContent > xContent
139 3 : = queryExistingContent( xCanonicId ).get();
140 :
141 3 : if ( !xContent.is() )
142 : {
143 : // Create a new content.
144 3 : xContent = Content::create( m_xContext, this, xCanonicId );
145 3 : registerNewContent( xContent );
146 : }
147 :
148 3 : return xContent;
149 : }
150 :
151 : //=========================================================================
152 : //
153 : // XTransientDocumentsDocumentContentFactory methods.
154 : //
155 : //=========================================================================
156 :
157 : // virtual
158 : uno::Reference< ucb::XContent > SAL_CALL
159 2 : ContentProvider::createDocumentContent(
160 : const uno::Reference< frame::XModel >& Model )
161 : throw ( lang::IllegalArgumentException, uno::RuntimeException )
162 : {
163 : // model -> id -> content identifier -> queryContent
164 2 : if ( m_xDocsMgr.is() )
165 : {
166 2 : rtl::OUString aDocId = m_xDocsMgr->queryDocumentId( Model );
167 2 : if ( !aDocId.isEmpty() )
168 : {
169 2 : rtl::OUStringBuffer aBuffer;
170 2 : aBuffer.appendAscii( TDOC_URL_SCHEME ":/" );
171 2 : aBuffer.append( aDocId );
172 :
173 : uno::Reference< ucb::XContentIdentifier > xId
174 2 : = new ::ucbhelper::ContentIdentifier( aBuffer.makeStringAndClear() );
175 :
176 2 : osl::MutexGuard aGuard( m_aMutex );
177 :
178 : // Check, if a content with given id already exists...
179 : uno::Reference< ucb::XContent > xContent
180 2 : = queryExistingContent( xId ).get();
181 :
182 2 : if ( !xContent.is() )
183 : {
184 : // Create a new content.
185 2 : xContent = Content::create( m_xContext, this, xId );
186 : }
187 :
188 2 : if ( xContent.is() )
189 4 : 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 2 : }
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 72 : void ContentProvider::notifyDocumentClosed( const rtl::OUString & rDocId )
225 : {
226 72 : osl::MutexGuard aGuard( getContentListMutex() );
227 :
228 72 : ::ucbhelper::ContentRefList aAllContents;
229 72 : queryExistingContents( aAllContents );
230 :
231 72 : ::ucbhelper::ContentRefList::const_iterator it = aAllContents.begin();
232 72 : ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end();
233 :
234 : // Notify all content objects related to the closed doc.
235 :
236 72 : bool bFoundDocumentContent = false;
237 72 : rtl::Reference< Content > xRoot;
238 :
239 144 : 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 72 : 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 72 : }
283 72 : }
284 :
285 : //=========================================================================
286 : // virtual
287 80 : void ContentProvider::notifyDocumentOpened( const rtl::OUString & rDocId )
288 : {
289 80 : osl::MutexGuard aGuard( getContentListMutex() );
290 :
291 80 : ::ucbhelper::ContentRefList aAllContents;
292 80 : queryExistingContents( aAllContents );
293 :
294 80 : ::ucbhelper::ContentRefList::const_iterator it = aAllContents.begin();
295 80 : ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end();
296 :
297 : // Find root content. If instanciated let it propagate document insertion.
298 :
299 160 : 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 80 : }
317 80 : }
318 :
319 : //=========================================================================
320 : //
321 : // Non-UNO
322 : //
323 : //=========================================================================
324 :
325 : uno::Reference< embed::XStorage >
326 5 : ContentProvider::queryStorage( const rtl::OUString & rUri,
327 : StorageAccessMode eMode ) const
328 : {
329 5 : if ( m_xStgElemFac.is() )
330 : {
331 : try
332 : {
333 5 : 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 5 : ContentProvider::queryStorageTitle( const rtl::OUString & rUri ) const
575 : {
576 5 : rtl::OUString aTitle;
577 :
578 5 : Uri aUri( rUri );
579 5 : if ( aUri.isRoot() )
580 : {
581 : // always empty.
582 0 : aTitle = rtl::OUString();
583 : }
584 5 : 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 5 : if ( m_xDocsMgr.is() )
589 5 : 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 5 : return aTitle;
600 : }
601 :
602 : //=========================================================================
603 : uno::Reference< frame::XModel >
604 3 : ContentProvider::queryDocumentModel( const rtl::OUString & rUri ) const
605 : {
606 3 : uno::Reference< frame::XModel > xModel;
607 :
608 3 : if ( m_xDocsMgr.is() )
609 : {
610 3 : Uri aUri( rUri );
611 3 : xModel = m_xDocsMgr->queryDocumentModel( aUri.getDocumentId() );
612 : }
613 :
614 : OSL_ENSURE( xModel.is(),
615 : "ContentProvider::queryDocumentModel - no model!" );
616 3 : return xModel;
617 : }
618 :
619 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|