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