xref: /trunk/main/ucb/source/ucp/tdoc/tdoc_provider.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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