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