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