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