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