xref: /trunk/main/ucbhelper/workben/myucp/myucp_content.cxx (revision 9d37da743abb7db0a497688391f6e55a19f27c44)
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_ucbhelper.hxx"
26 
27 /**************************************************************************
28                                 TODO
29  **************************************************************************
30 
31  *************************************************************************/
32 
33 #include "osl/diagnose.h"
34 
35 #include "com/sun/star/beans/PropertyAttribute.hpp"
36 #include "com/sun/star/beans/XPropertyAccess.hpp"
37 #include "com/sun/star/lang/IllegalAccessException.hpp"
38 #include "com/sun/star/sdbc/XRow.hpp"
39 #include "com/sun/star/ucb/XCommandInfo.hpp"
40 #include "com/sun/star/ucb/XPersistentPropertySet.hpp"
41 #include "ucbhelper/contentidentifier.hxx"
42 #include "ucbhelper/propertyvalueset.hxx"
43 #include "ucbhelper/cancelcommandexecution.hxx"
44 
45 #include "myucp_content.hxx"
46 #include "myucp_provider.hxx"
47 
48 #ifdef IMPLEMENT_COMMAND_INSERT
49 #include "com/sun/star/ucb/InsertCommandArgument.hpp"
50 #include "com/sun/star/ucb/MissingInputStreamException.hpp"
51 #include "com/sun/star/ucb/MissingPropertiesException.hpp"
52 #endif
53 #ifdef IMPLEMENT_COMMAND_OPEN
54 #include "com/sun/star/io/XOutputStream.hpp"
55 #include "com/sun/star/io/XActiveDataSink.hpp"
56 #include "com/sun/star/ucb/OpenCommandArgument2.hpp"
57 #include "com/sun/star/ucb/OpenMode.hpp"
58 #include "com/sun/star/ucb/UnsupportedDataSinkException.hpp"
59 #include "com/sun/star/ucb/UnsupportedOpenModeException.hpp"
60 #include "myucp_resultset.hxx"
61 #endif
62 
63 using namespace com::sun::star;
64 
65 // @@@ Adjust namespace name.
66 using namespace myucp;
67 
68 //=========================================================================
69 //=========================================================================
70 //
71 // Content Implementation.
72 //
73 //=========================================================================
74 //=========================================================================
75 
76 Content::Content( const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
77                   ::ucbhelper::ContentProviderImplHelper* pProvider,
78                   const uno::Reference< ucb::XContentIdentifier >& Identifier )
79 : ContentImplHelper( rxSMgr, pProvider, Identifier )
80 {
81     // @@@ Fill m_aProps here or implement lazy evaluation logic for this.
82     // m_aProps.aTitle       =
83     // m_aprops.aContentType =
84     // m_aProps.bIsDocument  =
85     // m_aProps.bIsFolder    =
86 }
87 
88 //=========================================================================
89 // virtual
90 Content::~Content()
91 {
92 }
93 
94 //=========================================================================
95 //
96 // XInterface methods.
97 //
98 //=========================================================================
99 
100 // virtual
101 void SAL_CALL Content::acquire()
102     throw()
103 {
104     ContentImplHelper::acquire();
105 }
106 
107 //=========================================================================
108 // virtual
109 void SAL_CALL Content::release()
110     throw()
111 {
112     ContentImplHelper::release();
113 }
114 
115 //=========================================================================
116 // virtual
117 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType )
118 {
119     uno::Any aRet;
120 
121     // @@@ Add support for additional interfaces.
122 #if 0
123     aRet = cppu::queryInterface( rType,
124                                  static_cast< yyy::Xxxxxxxxx * >( this ) );
125 #endif
126 
127     return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface( rType );
128 }
129 
130 //=========================================================================
131 //
132 // XTypeProvider methods.
133 //
134 //=========================================================================
135 
136 XTYPEPROVIDER_COMMON_IMPL( Content );
137 
138 //=========================================================================
139 // virtual
140 uno::Sequence< uno::Type > SAL_CALL Content::getTypes()
141 {
142     // @@@ Add own interfaces.
143 
144     static cppu::OTypeCollection* pCollection = 0;
145 
146     if ( !pCollection )
147     {
148         osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
149         if ( !pCollection )
150         {
151             static cppu::OTypeCollection aCollection(
152                 CPPU_TYPE_REF( lang::XTypeProvider ),
153                 CPPU_TYPE_REF( lang::XServiceInfo ),
154                 CPPU_TYPE_REF( lang::XComponent ),
155                 CPPU_TYPE_REF( ucb::XContent ),
156                 CPPU_TYPE_REF( ucb::XCommandProcessor ),
157                 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
158                 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
159                 CPPU_TYPE_REF( beans::XPropertyContainer ),
160                 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
161                 CPPU_TYPE_REF( container::XChild ) );
162             pCollection = &aCollection;
163         }
164     }
165 
166     return (*pCollection).getTypes();
167 }
168 
169 //=========================================================================
170 //
171 // XServiceInfo methods.
172 //
173 //=========================================================================
174 
175 // virtual
176 rtl::OUString SAL_CALL Content::getImplementationName()
177 {
178     // @@@ Adjust implementation name.
179     // Prefix with reversed company domain name.
180     return rtl::OUString::createFromAscii( "com.sun.star.comp.myucp.Content" );
181 }
182 
183 //=========================================================================
184 // virtual
185 uno::Sequence< rtl::OUString > SAL_CALL Content::getSupportedServiceNames()
186 {
187     // @@@ Adjust macro name.
188     uno::Sequence< rtl::OUString > aSNS( 1 );
189     aSNS.getArray()[ 0 ]
190             = rtl::OUString::createFromAscii( MYUCP_CONTENT_SERVICE_NAME );
191     return aSNS;
192 }
193 
194 //=========================================================================
195 //
196 // XContent methods.
197 //
198 //=========================================================================
199 
200 // virtual
201 rtl::OUString SAL_CALL Content::getContentType()
202 {
203     // @@@ Adjust macro name ( def in myucp_provider.hxx ).
204     return rtl::OUString::createFromAscii( MYUCP_CONTENT_TYPE );
205 }
206 
207 //=========================================================================
208 //
209 // XCommandProcessor methods.
210 //
211 //=========================================================================
212 
213 // virtual
214 uno::Any SAL_CALL Content::execute(
215         const ucb::Command& aCommand,
216         sal_Int32 /* CommandId */,
217         const uno::Reference< ucb::XCommandEnvironment >& Environment )
218 {
219     uno::Any aRet;
220 
221     if ( aCommand.Name.equalsAsciiL(
222             RTL_CONSTASCII_STRINGPARAM( "getPropertyValues" ) ) )
223     {
224         //////////////////////////////////////////////////////////////////
225         // getPropertyValues
226         //////////////////////////////////////////////////////////////////
227 
228         uno::Sequence< beans::Property > Properties;
229         if ( !( aCommand.Argument >>= Properties ) )
230         {
231             OSL_ENSURE( sal_False, "Wrong argument type!" );
232             ::ucbhelper::cancelCommandExecution(
233                 uno::makeAny( lang::IllegalArgumentException(
234                                     rtl::OUString(),
235                                     static_cast< cppu::OWeakObject * >( this ),
236                                     -1 ) ),
237                 Environment );
238             // Unreachable
239         }
240 
241         aRet <<= getPropertyValues( Properties, Environment );
242     }
243     else if ( aCommand.Name.equalsAsciiL(
244                 RTL_CONSTASCII_STRINGPARAM( "setPropertyValues" ) ) )
245     {
246         //////////////////////////////////////////////////////////////////
247         // setPropertyValues
248         //////////////////////////////////////////////////////////////////
249 
250         uno::Sequence< beans::PropertyValue > aProperties;
251         if ( !( aCommand.Argument >>= aProperties ) )
252         {
253             OSL_ENSURE( sal_False, "Wrong argument type!" );
254             ::ucbhelper::cancelCommandExecution(
255                 uno::makeAny( lang::IllegalArgumentException(
256                                     rtl::OUString(),
257                                     static_cast< cppu::OWeakObject * >( this ),
258                                     -1 ) ),
259                 Environment );
260             // Unreachable
261         }
262 
263         if ( !aProperties.getLength() )
264         {
265             OSL_ENSURE( sal_False, "No properties!" );
266             ::ucbhelper::cancelCommandExecution(
267                 uno::makeAny( lang::IllegalArgumentException(
268                                     rtl::OUString(),
269                                     static_cast< cppu::OWeakObject * >( this ),
270                                     -1 ) ),
271                 Environment );
272             // Unreachable
273         }
274 
275         aRet <<= setPropertyValues( aProperties, Environment );
276     }
277     else if ( aCommand.Name.equalsAsciiL(
278                 RTL_CONSTASCII_STRINGPARAM( "getPropertySetInfo" ) ) )
279     {
280         //////////////////////////////////////////////////////////////////
281         // getPropertySetInfo
282         //////////////////////////////////////////////////////////////////
283 
284         // Note: Implemented by base class.
285         aRet <<= getPropertySetInfo( Environment );
286     }
287     else if ( aCommand.Name.equalsAsciiL(
288                 RTL_CONSTASCII_STRINGPARAM( "getCommandInfo" ) ) )
289     {
290         //////////////////////////////////////////////////////////////////
291         // getCommandInfo
292         //////////////////////////////////////////////////////////////////
293 
294         // Note: Implemented by base class.
295         aRet <<= getCommandInfo( Environment );
296     }
297 #ifdef IMPLEMENT_COMMAND_OPEN
298     else if ( aCommand.Name.equalsAsciiL(
299                 RTL_CONSTASCII_STRINGPARAM( "open" ) ) )
300     {
301         ucb::OpenCommandArgument2 aOpenCommand;
302         if ( !( aCommand.Argument >>= aOpenCommand ) )
303         {
304             OSL_ENSURE( sal_False, "Wrong argument type!" );
305             ::ucbhelper::cancelCommandExecution(
306                 uno::makeAny( lang::IllegalArgumentException(
307                                     rtl::OUString(),
308                                     static_cast< cppu::OWeakObject * >( this ),
309                                     -1 ) ),
310                 Environment );
311             // Unreachable
312         }
313 
314         sal_Bool bOpenFolder =
315             ( ( aOpenCommand.Mode == ucb::OpenMode::ALL ) ||
316               ( aOpenCommand.Mode == ucb::OpenMode::FOLDERS ) ||
317               ( aOpenCommand.Mode == ucb::OpenMode::DOCUMENTS ) );
318 
319         if ( bOpenFolder /*&& isFolder( Environment )*/ )
320         {
321             // open as folder - return result set
322 
323             uno::Reference< ucb::XDynamicResultSet > xSet
324                             = new DynamicResultSet( m_xSMgr,
325                                                     this,
326                                                     aOpenCommand,
327                                                     Environment );
328             aRet <<= xSet;
329         }
330 
331         if ( aOpenCommand.Sink.is() )
332         {
333             // Open document - supply document data stream.
334 
335             // Check open mode
336             if ( ( aOpenCommand.Mode
337                     == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
338                  ( aOpenCommand.Mode
339                     == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) )
340             {
341                 // Unsupported.
342                 ::ucbhelper::cancelCommandExecution(
343                     uno::makeAny( ucb::UnsupportedOpenModeException(
344                                     rtl::OUString(),
345                                     static_cast< cppu::OWeakObject * >( this ),
346                                     sal_Int16( aOpenCommand.Mode ) ) ),
347                     Environment );
348                 // Unreachable
349             }
350 
351 
352             rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
353             uno::Reference< io::XOutputStream > xOut
354                 = uno::Reference< io::XOutputStream >(
355                     aOpenCommand.Sink, uno::UNO_QUERY );
356             if ( xOut.is() )
357             {
358                 // @@@ write data into xOut
359             }
360             else
361             {
362                 uno::Reference< io::XActiveDataSink > xDataSink(
363                         aOpenCommand.Sink, uno::UNO_QUERY );
364                 if ( xDataSink.is() )
365                 {
366                     uno::Reference< io::XInputStream > xIn
367                         /* @@@ your XInputStream + XSeekable impl. object */;
368                     xDataSink->setInputStream( xIn );
369                 }
370                 else
371                 {
372                     // Note: aOpenCommand.Sink may contain an XStream
373                     //       implementation. Support for this type of
374                     //       sink is optional...
375                     ::ucbhelper::cancelCommandExecution(
376                         uno::makeAny( ucb::UnsupportedDataSinkException(
377                                 rtl::OUString(),
378                                 static_cast< cppu::OWeakObject * >( this ),
379                                 aOpenCommand.Sink ) ),
380                         Environment );
381                     // Unreachable
382                 }
383             }
384         }
385     }
386 #endif // IMPLEMENT_COMMAND_OPEN
387 
388 #ifdef IMPLEMENT_COMMAND_INSERT
389     else if ( aCommand.Name.equalsAsciiL(
390                 RTL_CONSTASCII_STRINGPARAM( "insert" ) ) )
391     {
392         //////////////////////////////////////////////////////////////////
393         // insert
394         //////////////////////////////////////////////////////////////////
395 
396         ucb::InsertCommandArgument arg;
397         if ( !( aCommand.Argument >>= arg ) )
398         {
399             OSL_ENSURE( sal_False, "Wrong argument type!" );
400             ::ucbhelper::cancelCommandExecution(
401                 uno::makeAny( lang::IllegalArgumentException(
402                                     rtl::OUString(),
403                                     static_cast< cppu::OWeakObject * >( this ),
404                                     -1 ) ),
405                 Environment );
406             // Unreachable
407         }
408 
409         insert( arg.Data, arg.ReplaceExisting, Environment );
410     }
411 #endif // IMPLEMENT_COMMAND_INSERT
412 
413 #ifdef IMPLEMENT_COMMAND_DELETE
414     else if ( aCommand.Name.equalsAsciiL(
415                     RTL_CONSTASCII_STRINGPARAM( "delete" ) ) )
416     {
417         //////////////////////////////////////////////////////////////////
418         // delete
419         //////////////////////////////////////////////////////////////////
420 
421         sal_Bool bDeletePhysical = sal_False;
422         aCommand.Argument >>= bDeletePhysical;
423         destroy( bDeletePhysical );
424 
425         // Remove own and all children's Additional Core Properties.
426         removeAdditionalPropertySet( sal_True );
427 
428         // Remove own and all childrens(!) persistent data.
429 //      removeData();
430     }
431 #endif // IMPLEMENT_COMMAND_DELETE
432     else
433     {
434         //////////////////////////////////////////////////////////////////
435         // Unsupported command
436         //////////////////////////////////////////////////////////////////
437 
438         OSL_ENSURE( sal_False, "Content::execute - unsupported command!" );
439 
440         ::ucbhelper::cancelCommandExecution(
441             uno::makeAny( ucb::UnsupportedCommandException(
442                             rtl::OUString(),
443                             static_cast< cppu::OWeakObject * >( this ) ) ),
444             Environment );
445         // Unreachable
446     }
447 
448     return aRet;
449 }
450 
451 //=========================================================================
452 // virtual
453 void SAL_CALL Content::abort( sal_Int32 )
454 {
455     // @@@ Implement logic to abort running commands, if this makes
456     //     sense for your content.
457 }
458 
459 //=========================================================================
460 //
461 // Non-interface methods.
462 //
463 //=========================================================================
464 
465 // virtual
466 rtl::OUString Content::getParentURL()
467 {
468     rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
469 
470     // @@@ Extract URL of parent from aURL and return it...
471 
472     return rtl::OUString();
473 }
474 
475 //=========================================================================
476 // static
477 uno::Reference< sdbc::XRow > Content::getPropertyValues(
478             const uno::Reference< lang::XMultiServiceFactory >& rSMgr,
479             const uno::Sequence< beans::Property >& rProperties,
480             const ContentProperties& rData,
481             const rtl::Reference<
482                 ::ucbhelper::ContentProviderImplHelper >& rProvider,
483             const rtl::OUString& rContentId )
484 {
485     // Note: Empty sequence means "get values of all supported properties".
486 
487     rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
488         = new ::ucbhelper::PropertyValueSet( rSMgr );
489 
490     sal_Int32 nCount = rProperties.getLength();
491     if ( nCount )
492     {
493         uno::Reference< beans::XPropertySet > xAdditionalPropSet;
494         sal_Bool bTriedToGetAdditonalPropSet = sal_False;
495 
496         const beans::Property* pProps = rProperties.getConstArray();
497         for ( sal_Int32 n = 0; n < nCount; ++n )
498         {
499             const beans::Property& rProp = pProps[ n ];
500 
501             // Process Core properties.
502 
503             if ( rProp.Name.equalsAsciiL(
504                     RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) )
505             {
506                 xRow->appendString ( rProp, rData.aContentType );
507             }
508             else if ( rProp.Name.equalsAsciiL(
509                     RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
510             {
511                 xRow->appendString ( rProp, rData.aTitle );
512             }
513             else if ( rProp.Name.equalsAsciiL(
514                     RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) )
515             {
516                 xRow->appendBoolean( rProp, rData.bIsDocument );
517             }
518             else if ( rProp.Name.equalsAsciiL(
519                     RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) )
520             {
521                 xRow->appendBoolean( rProp, rData.bIsFolder );
522             }
523 
524             // @@@ Process other properties supported directly.
525 #if 0
526             else if ( rProp.Name.equalsAsciiL(
527                     RTL_CONSTASCII_STRINGPARAM( "xxxxxx" ) ) )
528             {
529             }
530 #endif
531             else
532             {
533                 // @@@ Note: If your data source supports adding/removing
534                 //     properties, you should implement the interface
535                 //     XPropertyContainer by yourself and supply your own
536                 //     logic here. The base class uses the service
537                 //     "com.sun.star.ucb.Store" to maintain Additional Core
538                 //     properties. But using server functionality is preferred!
539 
540                 // Not a Core Property! Maybe it's an Additional Core Property?!
541 
542                 if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() )
543                 {
544                     xAdditionalPropSet
545                         = uno::Reference< beans::XPropertySet >(
546                             rProvider->getAdditionalPropertySet( rContentId,
547                                                                  sal_False ),
548                             uno::UNO_QUERY );
549                     bTriedToGetAdditonalPropSet = sal_True;
550                 }
551 
552                 if ( xAdditionalPropSet.is() )
553                 {
554                     if ( !xRow->appendPropertySetValue(
555                                                 xAdditionalPropSet,
556                                                 rProp ) )
557                     {
558                         // Append empty entry.
559                         xRow->appendVoid( rProp );
560                     }
561                 }
562                 else
563                 {
564                     // Append empty entry.
565                     xRow->appendVoid( rProp );
566                 }
567             }
568         }
569     }
570     else
571     {
572         // Append all Core Properties.
573         xRow->appendString (
574             beans::Property( rtl::OUString::createFromAscii( "ContentType" ),
575                       -1,
576                       getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
577                       beans::PropertyAttribute::BOUND
578                         | beans::PropertyAttribute::READONLY ),
579             rData.aContentType );
580         xRow->appendString (
581             beans::Property( rtl::OUString::createFromAscii( "Title" ),
582                       -1,
583                       getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
584                       beans::PropertyAttribute::BOUND ),
585             rData.aTitle );
586         xRow->appendBoolean(
587             beans::Property( rtl::OUString::createFromAscii( "IsDocument" ),
588                       -1,
589                       getCppuBooleanType(),
590                       beans::PropertyAttribute::BOUND
591                         | beans::PropertyAttribute::READONLY ),
592             rData.bIsDocument );
593         xRow->appendBoolean(
594             beans::Property( rtl::OUString::createFromAscii( "IsFolder" ),
595                       -1,
596                       getCppuBooleanType(),
597                       beans::PropertyAttribute::BOUND
598                         | beans::PropertyAttribute::READONLY ),
599             rData.bIsFolder );
600 
601         // @@@ Append other properties supported directly.
602 
603         // @@@ Note: If your data source supports adding/removing
604         //     properties, you should implement the interface
605         //     XPropertyContainer by yourself and supply your own
606         //     logic here. The base class uses the service
607         //     "com.sun.star.ucb.Store" to maintain Additional Core
608         //     properties. But using server functionality is preferred!
609 
610         // Append all Additional Core Properties.
611 
612         uno::Reference< beans::XPropertySet > xSet(
613             rProvider->getAdditionalPropertySet( rContentId, sal_False ),
614             uno::UNO_QUERY );
615         xRow->appendPropertySet( xSet );
616     }
617 
618     return uno::Reference< sdbc::XRow >( xRow.get() );
619 }
620 
621 //=========================================================================
622 uno::Reference< sdbc::XRow > Content::getPropertyValues(
623             const uno::Sequence< beans::Property >& rProperties,
624             const uno::Reference< ucb::XCommandEnvironment >& /* xEnv */)
625 {
626     osl::Guard< osl::Mutex > aGuard( m_aMutex );
627     return getPropertyValues( m_xSMgr,
628                               rProperties,
629                               m_aProps,
630                               rtl::Reference<
631                                 ::ucbhelper::ContentProviderImplHelper >(
632                                     m_xProvider.get() ),
633                               m_xIdentifier->getContentIdentifier() );
634 }
635 
636 //=========================================================================
637 uno::Sequence< uno::Any > Content::setPropertyValues(
638             const uno::Sequence< beans::PropertyValue >& rValues,
639             const uno::Reference< ucb::XCommandEnvironment >& /* xEnv */)
640 {
641     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
642 
643     uno::Sequence< uno::Any > aRet( rValues.getLength() );
644     uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
645     sal_Int32 nChanged = 0;
646 
647     beans::PropertyChangeEvent aEvent;
648     aEvent.Source         = static_cast< cppu::OWeakObject * >( this );
649     aEvent.Further        = sal_False;
650 //  aEvent.PropertyName   =
651     aEvent.PropertyHandle = -1;
652 //  aEvent.OldValue       =
653 //  aEvent.NewValue       =
654 
655     const beans::PropertyValue* pValues = rValues.getConstArray();
656     sal_Int32 nCount = rValues.getLength();
657 
658     uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
659     sal_Bool bTriedToGetAdditonalPropSet = sal_False;
660 
661     for ( sal_Int32 n = 0; n < nCount; ++n )
662     {
663         const beans::PropertyValue& rValue = pValues[ n ];
664 
665         if ( rValue.Name.equalsAsciiL(
666                         RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) )
667         {
668             // Read-only property!
669             aRet[ n ] <<= lang::IllegalAccessException(
670                             rtl::OUString::createFromAscii(
671                                 "Property is read-only!" ),
672                             static_cast< cppu::OWeakObject * >( this ) );
673         }
674         else if ( rValue.Name.equalsAsciiL(
675                         RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) )
676         {
677             // Read-only property!
678             aRet[ n ] <<= lang::IllegalAccessException(
679                             rtl::OUString::createFromAscii(
680                                 "Property is read-only!" ),
681                             static_cast< cppu::OWeakObject * >( this ) );
682         }
683         else if ( rValue.Name.equalsAsciiL(
684                         RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) )
685         {
686             // Read-only property!
687             aRet[ n ] <<= lang::IllegalAccessException(
688                             rtl::OUString::createFromAscii(
689                                 "Property is read-only!" ),
690                             static_cast< cppu::OWeakObject * >( this ) );
691         }
692         else if ( rValue.Name.equalsAsciiL(
693                         RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
694         {
695             rtl::OUString aNewValue;
696             if ( rValue.Value >>= aNewValue )
697             {
698                 if ( aNewValue != m_aProps.aTitle )
699                 {
700                     aEvent.PropertyName = rValue.Name;
701                     aEvent.OldValue     = uno::makeAny( m_aProps.aTitle );
702                     aEvent.NewValue     = uno::makeAny( aNewValue );
703 
704                     aChanges.getArray()[ nChanged ] = aEvent;
705 
706                     m_aProps.aTitle = aNewValue;
707                     nChanged++;
708                 }
709                 else
710                 {
711                     // Old value equals new value. No error!
712                 }
713             }
714             else
715             {
716                 aRet[ n ] <<= beans::IllegalTypeException(
717                                 rtl::OUString::createFromAscii(
718                                     "Property value has wrong type!" ),
719                                 static_cast< cppu::OWeakObject * >( this ) );
720             }
721         }
722 
723         // @@@ Process other properties supported directly.
724 #if 0
725         else if ( rValue.Name.equalsAsciiL(
726                         RTL_CONSTASCII_STRINGPARAM( "xxxxxx" ) ) )
727         {
728         }
729 #endif
730         else
731         {
732             // @@@ Note: If your data source supports adding/removing
733             //     properties, you should implement the interface
734             //     XPropertyContainer by yourself and supply your own
735             //     logic here. The base class uses the service
736             //     "com.sun.star.ucb.Store" to maintain Additional Core
737             //     properties. But using server functionality is preferred!
738 
739             // Not a Core Property! Maybe it's an Additional Core Property?!
740 
741             if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() )
742             {
743                 xAdditionalPropSet = getAdditionalPropertySet( sal_False );
744                 bTriedToGetAdditonalPropSet = sal_True;
745             }
746 
747             if ( xAdditionalPropSet.is() )
748             {
749                 try
750                 {
751                     uno::Any aOldValue
752                         = xAdditionalPropSet->getPropertyValue( rValue.Name );
753                     if ( aOldValue != rValue.Value )
754                     {
755                         xAdditionalPropSet->setPropertyValue(
756                                                 rValue.Name, rValue.Value );
757 
758                         aEvent.PropertyName = rValue.Name;
759                         aEvent.OldValue     = aOldValue;
760                         aEvent.NewValue     = rValue.Value;
761 
762                         aChanges.getArray()[ nChanged ] = aEvent;
763                         nChanged++;
764                     }
765                     else
766                     {
767                         // Old value equals new value. No error!
768                     }
769                 }
770                 catch ( beans::UnknownPropertyException const & e )
771                 {
772                     aRet[ n ] <<= e;
773                 }
774                 catch ( lang::WrappedTargetException const & e )
775                 {
776                     aRet[ n ] <<= e;
777                 }
778                 catch ( beans::PropertyVetoException const & e )
779                 {
780                     aRet[ n ] <<= e;
781                 }
782                 catch ( lang::IllegalArgumentException const & e )
783                 {
784                     aRet[ n ] <<= e;
785                 }
786             }
787             else
788             {
789                 aRet[ n ] <<= uno::Exception(
790                                 rtl::OUString::createFromAscii(
791                                     "No property set for storing the value!" ),
792                                 static_cast< cppu::OWeakObject * >( this ) );
793             }
794         }
795     }
796 
797     if ( nChanged > 0 )
798     {
799         // @@@ Save changes.
800 //      storeData();
801 
802         aGuard.clear();
803         aChanges.realloc( nChanged );
804         notifyPropertiesChange( aChanges );
805     }
806 
807     return aRet;
808 }
809 
810 #ifdef IMPLEMENT_COMMAND_INSERT
811 
812 //=========================================================================
813 void Content::queryChildren( ContentRefList& rChildren )
814 {
815     // @@@ Adapt method to your URL scheme...
816 
817     // Obtain a list with a snapshot of all currently instantiated contents
818     // from provider and extract the contents which are direct children
819     // of this content.
820 
821     ::ucbhelper::ContentRefList aAllContents;
822     m_xProvider->queryExistingContents( aAllContents );
823 
824     ::rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
825     sal_Int32 nPos = aURL.lastIndexOf( '/' );
826 
827     if ( nPos != ( aURL.getLength() - 1 ) )
828     {
829         // No trailing slash found. Append.
830         aURL += ::rtl::OUString::createFromAscii( "/" );
831     }
832 
833     sal_Int32 nLen = aURL.getLength();
834 
835     ::ucbhelper::ContentRefList::const_iterator it  = aAllContents.begin();
836     ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end();
837 
838     while ( it != end )
839     {
840         ::ucbhelper::ContentImplHelperRef xChild = (*it);
841         ::rtl::OUString aChildURL
842               = xChild->getIdentifier()->getContentIdentifier();
843 
844         // Is aURL a prefix of aChildURL?
845         if ( ( aChildURL.getLength() > nLen ) &&
846              ( aChildURL.compareTo( aURL, nLen ) == 0 ) )
847         {
848             nPos = aChildURL.indexOf( '/', nLen );
849 
850             if ( ( nPos == -1 ) ||
851                  ( nPos == ( aChildURL.getLength() - 1 ) ) )
852             {
853                 // No further slashes / only a final slash. It's a child!
854                 rChildren.push_back(
855                     ContentRef(
856                         static_cast< Content * >( xChild.get() ) ) );
857             }
858         }
859         ++it;
860     }
861 }
862 
863 //=========================================================================
864 void Content::insert(
865         const uno::Reference< io::XInputStream > & xInputStream,
866         sal_Bool bReplaceExisting,
867         const uno::Reference< ucb::XCommandEnvironment >& Environment )
868 {
869     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
870 
871     // Check, if all required properties were set.
872 
873 #if 0
874     // @@@ add checks for property presence
875     if ( m_aProps.xxxx == yyyyy )
876     {
877         OSL_ENSURE( sal_False, "Content::insert - property value missing!" );
878 
879         uno::Sequence< rtl::OUString > aProps( 1 );
880         aProps[ 0 ] = rtl::OUString::createFromAscii( "zzzz" );
881         ::ucbhelper::cancelCommandExecution(
882             uno::makeAny( ucb::MissingPropertiesException(
883                                 rtl::OUString(),
884                                 static_cast< cppu::OWeakObject * >( this ),
885                                 aProps ) ),
886             Environment );
887         // Unreachable
888     }
889 #endif
890 
891     bool bNeedInputStream = true; // @@@ adjust to real requirements
892     if ( bNeedInputStream && !xInputStream.is() )
893     {
894         OSL_ENSURE( sal_False, "Content::insert - No data stream!" );
895 
896         ::ucbhelper::cancelCommandExecution(
897             uno::makeAny( ucb::MissingInputStreamException(
898                             rtl::OUString(),
899                             static_cast< cppu::OWeakObject * >( this ) ) ),
900             Environment );
901         // Unreachable
902     }
903 
904     // Assemble new content identifier...
905 
906     uno::Reference< ucb::XContentIdentifier > xId /* @@@ create content identifier */;
907 
908     // Fail, if a resource with given id already exists.
909     if ( !bReplaceExisting /*&& hasData( xId ) @@@ impl for hasData() */ )
910     {
911         uno::Any aProps
912             = uno::makeAny( beans::PropertyValue(
913                                   rtl::OUString(
914                                       RTL_CONSTASCII_USTRINGPARAM( "Uri" ) ),
915                                   -1,
916                                   uno::makeAny( xId->getContentIdentifier() ),
917                                   beans::PropertyState_DIRECT_VALUE ) );
918         ucbhelper::cancelCommandExecution(
919             ucb::IOErrorCode_ALREADY_EXISTING,
920             uno::Sequence< uno::Any >(&aProps, 1),
921             Environment,
922             rtl::OUString::createFromAscii( "content already existing!!" ),
923             this );
924         // Unreachable
925     }
926 
927     m_xIdentifier = xId;
928 
929 //  @@@
930 //  storeData();
931 
932     aGuard.clear();
933     inserted();
934 }
935 
936 #endif // IMPLEMENT_COMMAND_INSERT
937 
938 #ifdef IMPLEMENT_COMMAND_DELETE
939 
940 //=========================================================================
941 void Content::destroy( sal_Bool bDeletePhysical )
942 {
943     // @@@ take care about bDeletePhysical -> trashcan support
944 
945     uno::Reference< ucb::XContent > xThis = this;
946 
947     deleted();
948 
949     osl::Guard< osl::Mutex > aGuard( m_aMutex );
950 
951     // Process instantiated children...
952 
953     ContentRefList aChildren;
954     queryChildren( aChildren );
955 
956     ContentRefList::const_iterator it  = aChildren.begin();
957     ContentRefList::const_iterator end = aChildren.end();
958 
959     while ( it != end )
960     {
961         (*it)->destroy( bDeletePhysical );
962         ++it;
963     }
964 }
965 
966 #endif // IMPLEMENT_COMMAND_DELETE
967