/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_ucb.hxx"

/**************************************************************************
								TODO
 **************************************************************************

  *************************************************************************/

#include <list>
#include <hash_map>
#include <osl/diagnose.h>
#include <rtl/ustrbuf.hxx>
#include <cppuhelper/interfacecontainer.hxx>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/beans/PropertySetInfoChange.hpp>
#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/container/XNameReplace.hpp>
#include <com/sun/star/util/XChangesBatch.hpp>
#include "ucbstore.hxx"

using namespace com::sun::star::beans;
using namespace com::sun::star::container;
using namespace com::sun::star::lang;
using namespace com::sun::star::ucb;
using namespace com::sun::star::uno;
using namespace com::sun::star::util;
using namespace cppu;
using namespace rtl;

//=========================================================================
rtl::OUString makeHierarchalNameSegment( const rtl::OUString & rIn  )
{
    rtl::OUStringBuffer aBuffer;
    aBuffer.appendAscii( "['" );

    sal_Int32 nCount = rIn.getLength();
    for ( sal_Int32 n = 0; n < nCount; ++n )
    {
        const sal_Unicode c = rIn.getStr()[ n ];
        switch ( c )
        {
            case '&':
                aBuffer.appendAscii( "&amp;" );
                break;

            case '"':
                aBuffer.appendAscii( "&quot;" );
                break;

            case '\'':
                aBuffer.appendAscii( "&apos;" );
                break;

            case '<':
                aBuffer.appendAscii( "&lt;" );
                break;

            case '>':
                aBuffer.appendAscii( "&gt;" );
                break;

            default:
                aBuffer.append( c );
                break;
        }
    }

    aBuffer.appendAscii( "']" );
    return rtl::OUString( aBuffer.makeStringAndClear() );
}

//=========================================================================

#define STORE_CONTENTPROPERTIES_KEY	"/org.openoffice.ucb.Store/ContentProperties"

// describe path of cfg entry
#define	CFGPROPERTY_NODEPATH		"nodepath"
// true->async. update; false->sync. update
#define	CFGPROPERTY_LAZYWRITE		"lazywrite"

//=========================================================================

struct equalString_Impl
{
  bool operator()( const OUString& s1, const OUString& s2 ) const
  {
		return !!( s1 == s2 );
  }
};

struct hashString_Impl
{
	size_t operator()( const OUString & rName ) const
	{
		return rName.hashCode();
	}
};

//=========================================================================
//
// PropertySetMap_Impl.
//
//=========================================================================

typedef std::hash_map
<
	OUString,
	PersistentPropertySet*,
	hashString_Impl,
	equalString_Impl
>
PropertySetMap_Impl;

//=========================================================================
//
// class PropertySetInfo_Impl
//
//=========================================================================

class PropertySetInfo_Impl :
		public OWeakObject,	public XTypeProvider, public XPropertySetInfo
{
	Reference< XMultiServiceFactory > m_xSMgr;
	Sequence< Property >* 			  m_pProps;
	PersistentPropertySet*			  m_pOwner;

public:
	PropertySetInfo_Impl( const Reference< XMultiServiceFactory >& rxSMgr,
	                      PersistentPropertySet* pOwner );
	virtual ~PropertySetInfo_Impl();

	// XInterface
	XINTERFACE_DECL()

	// XTypeProvider
	XTYPEPROVIDER_DECL()

	// XPropertySetInfo
    virtual Sequence< Property > SAL_CALL getProperties()
		throw( RuntimeException );
    virtual Property SAL_CALL getPropertyByName( const OUString& aName )
		throw( UnknownPropertyException, RuntimeException );
    virtual sal_Bool SAL_CALL hasPropertyByName( const OUString& Name )
		throw( RuntimeException );

	// Non-interface methods.
	void reset() { delete m_pProps; m_pProps = 0; }
};

//=========================================================================
//
// UcbStore_Impl.
//
//=========================================================================

struct UcbStore_Impl
{
	osl::Mutex						  m_aMutex;
	Sequence< Any > 				  m_aInitArgs;
	Reference< XPropertySetRegistry > m_xTheRegistry;
};

//=========================================================================
//=========================================================================
//=========================================================================
//
// UcbStore Implementation.
//
//=========================================================================
//=========================================================================
//=========================================================================

UcbStore::UcbStore(	const Reference< XMultiServiceFactory >& rXSMgr )
: m_xSMgr( rXSMgr ),
  m_pImpl( new UcbStore_Impl() )
{
}

//=========================================================================
// virtual
UcbStore::~UcbStore()
{
	delete m_pImpl;
}

//=========================================================================
//
// XInterface methods.
//
//=========================================================================

XINTERFACE_IMPL_4( UcbStore,
				   XTypeProvider,
				   XServiceInfo,
				   XPropertySetRegistryFactory,
				   XInitialization );

//=========================================================================
//
// XTypeProvider methods.
//
//=========================================================================

XTYPEPROVIDER_IMPL_4( UcbStore,
				   	  XTypeProvider,
				   	  XServiceInfo,
					  XPropertySetRegistryFactory,
					  XInitialization );

//=========================================================================
//
// XServiceInfo methods.
//
//=========================================================================

XSERVICEINFO_IMPL_1( UcbStore,
					 OUString::createFromAscii(
					 	"com.sun.star.comp.ucb.UcbStore" ),
					 OUString::createFromAscii(
					 	STORE_SERVICE_NAME ) );

//=========================================================================
//
// Service factory implementation.
//
//=========================================================================

ONE_INSTANCE_SERVICE_FACTORY_IMPL( UcbStore );

//=========================================================================
//
// XPropertySetRegistryFactory methods.
//
//=========================================================================

// virtual
Reference< XPropertySetRegistry > SAL_CALL
UcbStore::createPropertySetRegistry( const OUString& )
	throw( RuntimeException )
{
	// The URL parameter is ignored by this interface implementation. It always
    // uses the configuration server as storage medium.

	if ( !m_pImpl->m_xTheRegistry.is() )
	{
		osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
		if ( !m_pImpl->m_xTheRegistry.is() )
			m_pImpl->m_xTheRegistry = new PropertySetRegistry( m_xSMgr, getInitArgs() );
	}

	return m_pImpl->m_xTheRegistry;
}

//=========================================================================
//
// XInitialization methods.
//
//=========================================================================

// virtual
void SAL_CALL UcbStore::initialize( const Sequence< Any >& aArguments )
	throw( Exception, RuntimeException )
{
	osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
	m_pImpl->m_aInitArgs = aArguments;
}

//=========================================================================
const Sequence< Any >& UcbStore::getInitArgs() const
{
	return m_pImpl->m_aInitArgs;
}

//=========================================================================
//
// PropertySetRegistry_Impl.
//
//=========================================================================

struct PropertySetRegistry_Impl
{
	const Sequence< Any >			  m_aInitArgs;
	PropertySetMap_Impl 			  m_aPropSets;
	Reference< XMultiServiceFactory > m_xConfigProvider;
	Reference< XInterface >			  m_xRootReadAccess;
	Reference< XInterface >			  m_xRootWriteAccess;
	osl::Mutex						  m_aMutex;
	sal_Bool			  			  m_bTriedToGetRootReadAccess;  // #82494#
	sal_Bool			  			  m_bTriedToGetRootWriteAccess; // #82494#

	PropertySetRegistry_Impl( const Sequence< Any > &rInitArgs )
	: m_aInitArgs( rInitArgs ),
	  m_bTriedToGetRootReadAccess( sal_False ),
	  m_bTriedToGetRootWriteAccess( sal_False )
	{
	}
};

//=========================================================================
//=========================================================================
//=========================================================================
//
// PropertySetRegistry Implementation.
//
//=========================================================================
//=========================================================================
//=========================================================================

PropertySetRegistry::PropertySetRegistry(
						const Reference< XMultiServiceFactory >& rXSMgr,
						const Sequence< Any > &rInitArgs )
: m_xSMgr( rXSMgr ),
  m_pImpl( new PropertySetRegistry_Impl( rInitArgs ) )
{
}

//=========================================================================
// virtual
PropertySetRegistry::~PropertySetRegistry()
{
	delete m_pImpl;
}

//=========================================================================
//
// XInterface methods.
//
//=========================================================================

XINTERFACE_IMPL_5( PropertySetRegistry,
				   XTypeProvider,
				   XServiceInfo,
				   XPropertySetRegistry,
				   XElementAccess, /* base of XNameAccess */
				   XNameAccess );

//=========================================================================
//
// XTypeProvider methods.
//
//=========================================================================

XTYPEPROVIDER_IMPL_4( PropertySetRegistry,
				   	  XTypeProvider,
					  XServiceInfo,
					  XPropertySetRegistry,
					  XNameAccess );

//=========================================================================
//
// XServiceInfo methods.
//
//=========================================================================

XSERVICEINFO_NOFACTORY_IMPL_1( PropertySetRegistry,
					 		   OUString::createFromAscii(
				   				"com.sun.star.comp.ucb.PropertySetRegistry" ),
					 		   OUString::createFromAscii(
				   				PROPSET_REG_SERVICE_NAME ) );

//=========================================================================
//
// XPropertySetRegistry methods.
//
//=========================================================================

// virtual
Reference< XPersistentPropertySet > SAL_CALL
PropertySetRegistry::openPropertySet( const OUString& key, sal_Bool create )
	throw( RuntimeException )
{
	if ( key.getLength() )
	{
		osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

		PropertySetMap_Impl& rSets = m_pImpl->m_aPropSets;

		PropertySetMap_Impl::const_iterator it = rSets.find( key );
		if ( it != rSets.end() )
		{
			// Already instanciated.
			return Reference< XPersistentPropertySet >( (*it).second );
		}
		else
		{
			// Create new instance.
            Reference< XNameAccess > xRootNameAccess(
									getRootConfigReadAccess(), UNO_QUERY );
            if ( xRootNameAccess.is() )
			{
				// Propertyset in registry?
                if ( xRootNameAccess->hasByName( key ) )
				{
					// Yep!
					return Reference< XPersistentPropertySet >(
											new PersistentPropertySet(
													m_xSMgr, *this, key ) );
				}
				else if ( create )
				{
					// No. Create entry for propertyset.

					Reference< XSingleServiceFactory > xFac(
							getConfigWriteAccess( OUString() ), UNO_QUERY );
					Reference< XChangesBatch >  xBatch( xFac, UNO_QUERY );
					Reference< XNameContainer > xContainer( xFac, UNO_QUERY );

					OSL_ENSURE( xFac.is(),
								"PropertySetRegistry::openPropertySet - "
								"No factory!" );

					OSL_ENSURE( xBatch.is(),
								"PropertySetRegistry::openPropertySet - "
								"No batch!" );

					OSL_ENSURE( xContainer.is(),
								"PropertySetRegistry::openPropertySet - "
								"No conteiner!" );

					if ( xFac.is() && xBatch.is() && xContainer.is() )
					{
						try
						{
							// Create new "Properties" config item.
							Reference< XNameReplace > xNameReplace(
										xFac->createInstance(), UNO_QUERY );

							if ( xNameReplace.is() )
							{
								// Fill new item...

//								// Set Values
//								xNameReplace->replaceByName(
//										OUString::createFromAscii( "Values" ),
//										makeAny( ... ) );

								// Insert new item.
								xContainer->insertByName(
                                        key, makeAny( xNameReplace ) );
								// Commit changes.
								xBatch->commitChanges();

								return Reference< XPersistentPropertySet >(
											new PersistentPropertySet(
													m_xSMgr, *this, key ) );
							}
						}
						catch ( IllegalArgumentException& )
						{
							// insertByName

							OSL_ENSURE( sal_False,
										"PropertySetRegistry::openPropertySet - "
										"caught IllegalArgumentException!" );
						}
						catch ( ElementExistException& )
						{
							// insertByName

							OSL_ENSURE( sal_False,
										"PropertySetRegistry::openPropertySet - "
										"caught ElementExistException!" );
						}
						catch ( WrappedTargetException& )
						{
							// insertByName, commitChanges

							OSL_ENSURE( sal_False,
										"PropertySetRegistry::openPropertySet - "
										"caught WrappedTargetException!" );
						}
						catch ( RuntimeException& )
						{
							OSL_ENSURE( sal_False,
										"PropertySetRegistry::openPropertySet - "
										"caught RuntimeException!" );
						}
						catch ( Exception& )
						{
							// createInstance

							OSL_ENSURE( sal_False,
										"PropertySetRegistry::openPropertySet - "
										"caught Exception!" );
						}
					}
				}
				else
				{
					// No entry. Fail, but no error.
					return Reference< XPersistentPropertySet >();
				}
			}

			OSL_ENSURE( sal_False,
						"PropertySetRegistry::openPropertySet - Error!" );
		}
	}

	return Reference< XPersistentPropertySet >();
}

//=========================================================================
// virtual
void SAL_CALL PropertySetRegistry::removePropertySet( const OUString& key )
	throw( RuntimeException )
{
	if ( !key.getLength() )
		return;

	osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

    Reference< XNameAccess > xRootNameAccess(
									getRootConfigReadAccess(), UNO_QUERY );
    if ( xRootNameAccess.is() )
	{
		// Propertyset in registry?
        if ( !xRootNameAccess->hasByName( key ) )
			return;
		Reference< XChangesBatch > xBatch(
							getConfigWriteAccess( OUString() ), UNO_QUERY );
		Reference< XNameContainer > xContainer( xBatch, UNO_QUERY );

		OSL_ENSURE( xBatch.is(),
					"PropertySetRegistry::removePropertySet - "
					"No batch!" );

		OSL_ENSURE( xContainer.is(),
					"PropertySetRegistry::removePropertySet - "
					"No conteiner!" );

		if ( xBatch.is() && xContainer.is() )
		{
			try
			{
				// Remove item.
                xContainer->removeByName( key );
				// Commit changes.
				xBatch->commitChanges();

				// Success.
				return;
			}
			catch ( NoSuchElementException& )
			{
				// removeByName

				OSL_ENSURE( sal_False,
							"PropertySetRegistry::removePropertySet - "
							"caught NoSuchElementException!" );
				return;
			}
			catch ( WrappedTargetException& )
			{
				// commitChanges

				OSL_ENSURE( sal_False,
							"PropertySetRegistry::removePropertySet - "
							"caught WrappedTargetException!" );
				return;
			}
		}

		return;
	}

	OSL_ENSURE( sal_False, "PropertySetRegistry::removePropertySet - Error!" );
}

//=========================================================================
//
// XElementAccess methods.
//
//=========================================================================

// virtual
com::sun::star::uno::Type SAL_CALL PropertySetRegistry::getElementType()
	throw( RuntimeException )
{
	return getCppuType( ( Reference< XPersistentPropertySet > * ) 0 );
}

//=========================================================================
// virtual
sal_Bool SAL_CALL PropertySetRegistry::hasElements()
	throw( RuntimeException )
{
	osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

	Reference< XElementAccess > xElemAccess(
									getRootConfigReadAccess(), UNO_QUERY );
	if ( xElemAccess.is() )
		return xElemAccess->hasElements();

	return sal_False;
}

//=========================================================================
//
// XNameAccess methods.
//
//=========================================================================

// virtual
Any SAL_CALL PropertySetRegistry::getByName( const OUString& aName )
	throw( NoSuchElementException, WrappedTargetException, RuntimeException )
{
	osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

	Reference< XNameAccess > xNameAccess(
									getRootConfigReadAccess(), UNO_QUERY );
	if ( xNameAccess.is() )
	{

		try
		{
            return xNameAccess->getByName( aName );
		}
		catch ( NoSuchElementException& )
		{
			// getByName
		}
		catch ( WrappedTargetException& )
		{
			// getByName
		}
	}

	return Any();
}

//=========================================================================
// virtual
Sequence< OUString > SAL_CALL PropertySetRegistry::getElementNames()
	throw( RuntimeException )
{
	osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

	Reference< XNameAccess > xNameAccess(
									getRootConfigReadAccess(), UNO_QUERY );
	if ( xNameAccess.is() )
	{
        return xNameAccess->getElementNames();
	}
	return Sequence< OUString >( 0 );
}

//=========================================================================
// virtual
sal_Bool SAL_CALL PropertySetRegistry::hasByName( const OUString& aName )
	throw( RuntimeException )
{
	osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

	Reference< XNameAccess > xNameAccess(
									getRootConfigReadAccess(), UNO_QUERY );
	if ( xNameAccess.is() )
	{
        return xNameAccess->hasByName( aName );
	}

	return sal_False;
}

//=========================================================================
void PropertySetRegistry::add( PersistentPropertySet* pSet )
{
	OUString key( pSet->getKey() );

	if ( key.getLength() )
	{
		osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
		m_pImpl->m_aPropSets[ key ] = pSet;
	}
}

//=========================================================================
void PropertySetRegistry::remove( PersistentPropertySet* pSet )
{
	OUString key( pSet->getKey() );

	if ( key.getLength() )
	{
		osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

		PropertySetMap_Impl& rSets = m_pImpl->m_aPropSets;

		PropertySetMap_Impl::iterator it = rSets.find( key );
		if ( it != rSets.end() )
		{
			// Found.
			rSets.erase( it );
		}
	}
}

//=========================================================================
void PropertySetRegistry::renamePropertySet( const OUString& rOldKey,
										     const OUString& rNewKey )
{
	if ( rOldKey == rNewKey )
		return;

    Reference< XNameAccess > xRootNameAccess(
							getConfigWriteAccess( OUString() ), UNO_QUERY );
    if ( xRootNameAccess.is() )
	{
        // Old key present?
        if ( xRootNameAccess->hasByName( rOldKey ) )
        {
            // New key not present?
            if ( xRootNameAccess->hasByName( rNewKey ) )
            {
                OSL_ENSURE( sal_False,
                            "PropertySetRegistry::renamePropertySet - "
                            "New key exists!" );
                return;
            }
            Reference< XSingleServiceFactory > xFac(
                                                xRootNameAccess, UNO_QUERY );
            Reference< XChangesBatch >  xBatch( xFac, UNO_QUERY );
            Reference< XNameContainer > xContainer( xFac, UNO_QUERY );

            OSL_ENSURE( xFac.is(),
                        "PropertySetRegistry::renamePropertySet - "
                        "No factory!" );

            OSL_ENSURE( xBatch.is(),
                        "PropertySetRegistry::renamePropertySet - "
                        "No batch!" );

            OSL_ENSURE( xContainer.is(),
                        "PropertySetRegistry::renamePropertySet - "
                        "No container!" );

            if ( xFac.is() && xBatch.is() && xContainer.is() )
            {
                //////////////////////////////////////////////////////
                // Create new "Properties" config item.
                //////////////////////////////////////////////////////

                try
                {
                    Reference< XNameReplace > xNameReplace(
                                    xFac->createInstance(), UNO_QUERY );

                    if ( xNameReplace.is() )
                    {
                        // Insert new item.
                        xContainer->insertByName(
                                    rNewKey, makeAny( xNameReplace ) );
                        // Commit changes.
                        xBatch->commitChanges();
                    }
                }
                catch ( IllegalArgumentException& )
                {
                    // insertByName

                    OSL_ENSURE( sal_False,
                                "PropertySetRegistry::renamePropertySet - "
                                "caught IllegalArgumentException!" );
                    return;
                }
                catch ( ElementExistException& )
                {
                    // insertByName

                    OSL_ENSURE( sal_False,
                                "PropertySetRegistry::renamePropertySet - "
                                "caught ElementExistException!" );
                    return;
                }
                catch ( WrappedTargetException& )
                {
                    // insertByName, commitChanges

                    OSL_ENSURE( sal_False,
                                "PropertySetRegistry::renamePropertySet - "
                                "caught WrappedTargetException!" );
                    return;
                }
                catch ( RuntimeException& )
                {
                    OSL_ENSURE( sal_False,
                                "PropertySetRegistry::renamePropertySet - "
                                "caught RuntimeException!" );
                    return;
                }
                catch ( Exception& )
                {
                    // createInstance

                    OSL_ENSURE( sal_False,
                                "PropertySetRegistry::renamePropertySet - "
                                "caught Exception!" );
                    return;
                }

                //////////////////////////////////////////////////////
                // Copy data...
                //////////////////////////////////////////////////////

                Reference< XHierarchicalNameAccess > xRootHierNameAccess(
                                                xRootNameAccess, UNO_QUERY );
                if ( !xRootHierNameAccess.is() )
                {
                    OSL_ENSURE( sal_False,
                                "PropertySetRegistry::renamePropertySet - "
                                "No hierarchical name access!" );
                    return;
                }

                try
                {
                    rtl::OUString aOldValuesKey
                        = makeHierarchalNameSegment( rOldKey );
                    aOldValuesKey += OUString::createFromAscii( "/Values" );

                    Reference< XNameAccess > xOldNameAccess;
                    xRootHierNameAccess->getByHierarchicalName(
                                                        aOldValuesKey )
                        >>= xOldNameAccess;
                    if ( !xOldNameAccess.is() )
                    {
                        OSL_ENSURE( sal_False,
                            "PersistentPropertySet::renamePropertySet - "
                            "No old name access!" );
                        return;
                    }

                    // Obtain property names.
                    Sequence< OUString > aElems
                                    = xOldNameAccess->getElementNames();
                    sal_Int32 nCount = aElems.getLength();
                    if ( nCount )
                    {
                        rtl::OUString aNewValuesKey
                            = makeHierarchalNameSegment( rNewKey );
                        aNewValuesKey += OUString::createFromAscii( "/Values" );

                        Reference< XSingleServiceFactory > xNewFac;
                        xRootHierNameAccess->getByHierarchicalName(
                                                        aNewValuesKey )
                            >>= xNewFac;
                        if ( !xNewFac.is() )
                        {
                            OSL_ENSURE( sal_False,
                                "PersistentPropertySet::renamePropertySet - "
                                "No new factory!" );
                            return;
                        }

                        Reference< XNameContainer > xNewContainer(
                                                    xNewFac, UNO_QUERY );
                        if ( !xNewContainer.is() )
                        {
                            OSL_ENSURE( sal_False,
                                "PersistentPropertySet::renamePropertySet - "
                                "No new container!" );
                            return;
                        }

                        aOldValuesKey += OUString::createFromAscii( "/" );

                        OUString aHandleKey
                            = OUString::createFromAscii( "/Handle" );
                        OUString aValueKey
                            = OUString::createFromAscii( "/Value" );
                        OUString aStateKey
                            = OUString::createFromAscii( "/State" );
                        OUString aAttrKey
                            = OUString::createFromAscii( "/Attributes" );

                        for ( sal_Int32 n = 0; n < nCount; ++n )
                        {
                            const OUString& rPropName = aElems[ n ];

                            // Create new item.
                            Reference< XNameReplace > xNewPropNameReplace(
                                xNewFac->createInstance(), UNO_QUERY );

                            if ( !xNewPropNameReplace.is() )
                            {
                                OSL_ENSURE( sal_False,
                                    "PersistentPropertySet::renamePropertySet - "
                                    "No new prop name replace!" );
                                return;
                            }

                            // Fill new item...

                            // Set Values
                            OUString aKey = aOldValuesKey;
                            aKey += makeHierarchalNameSegment( rPropName );

                            // ... handle
                            OUString aNewKey1 = aKey;
                            aNewKey1 += aHandleKey;
                            Any aAny =
                                xRootHierNameAccess->getByHierarchicalName(
                                    aNewKey1 );
                            xNewPropNameReplace->replaceByName(
                                OUString::createFromAscii( "Handle" ),
                                aAny );

                            // ... value
                            aNewKey1 = aKey;
                            aNewKey1 += aValueKey;
                            aAny =
                                xRootHierNameAccess->getByHierarchicalName(
                                    aNewKey1 );
                            xNewPropNameReplace->replaceByName(
                                OUString::createFromAscii( "Value" ),
                                aAny );

                            // ... state
                            aNewKey1 = aKey;
                            aNewKey1 += aStateKey;
                            aAny =
                                xRootHierNameAccess->getByHierarchicalName(
                                    aNewKey1 );
                            xNewPropNameReplace->replaceByName(
                                OUString::createFromAscii( "State" ),
                                aAny );

                            // ... attributes
                            aNewKey1 = aKey;
                            aNewKey1 += aAttrKey;
                            aAny =
                                xRootHierNameAccess->getByHierarchicalName(
                                    aNewKey1 );
                            xNewPropNameReplace->replaceByName(
                                OUString::createFromAscii( "Attributes" ),
                                aAny );

                            // Insert new item.
                            xNewContainer->insertByName(
                                rPropName, makeAny( xNewPropNameReplace ) );

                            // Commit changes.
                            xBatch->commitChanges();
                        }
                    }
                }
                catch ( IllegalArgumentException& )
                {
                    // insertByName, replaceByName

                    OSL_ENSURE( sal_False,
                                "PropertySetRegistry::renamePropertySet - "
                                "caught IllegalArgumentException!" );
                    return;
                }
                catch ( ElementExistException& )
                {
                    // insertByName

                    OSL_ENSURE( sal_False,
                                "PropertySetRegistry::renamePropertySet - "
                                "caught ElementExistException!" );
                    return;
                }
                catch ( WrappedTargetException& )
                {
                    // insertByName, replaceByName, commitChanges

                    OSL_ENSURE( sal_False,
                                "PropertySetRegistry::renamePropertySet - "
                                "caught WrappedTargetException!" );
                    return;
                }
                catch ( NoSuchElementException& )
                {
                    // getByHierarchicalName, replaceByName

                    OSL_ENSURE( sal_False,
                                "PropertySetRegistry::renamePropertySet - "
                                "caught NoSuchElementException!" );
                    return;
                }
                catch ( RuntimeException& )
                {
                    OSL_ENSURE( sal_False,
                                "PropertySetRegistry::renamePropertySet - "
                                "caught RuntimeException!" );
                    return;
                }
                catch ( Exception& )
                {
                    // createInstance

                    OSL_ENSURE( sal_False,
                                "PropertySetRegistry::renamePropertySet - "
                                "caught Exception!" );
                    return;
                }

                //////////////////////////////////////////////////////
                // Remove old entry...
                //////////////////////////////////////////////////////

                try
                {
                    // Remove item.
                    xContainer->removeByName( rOldKey );
                    // Commit changes.
                    xBatch->commitChanges();

                    // Success.
                    return;
                }
                catch ( NoSuchElementException& )
                {
                    // removeByName

                    OSL_ENSURE( sal_False,
                                "PropertySetRegistry::renamePropertySet - "
                                "caught NoSuchElementException!" );
                    return;
                }
                catch ( WrappedTargetException& )
                {
                    // commitChanges

                    OSL_ENSURE( sal_False,
                                "PropertySetRegistry::renamePropertySet - "
                                "caught WrappedTargetException!" );
                    return;
                }
            }
        }
	}

	OSL_ENSURE( sal_False, "PropertySetRegistry::renamePropertySet - Error!" );
}

//=========================================================================
Reference< XMultiServiceFactory > PropertySetRegistry::getConfigProvider()
{
	if ( !m_pImpl->m_xConfigProvider.is() )
	{
		osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
		if ( !m_pImpl->m_xConfigProvider.is() )
		{
			const Sequence< Any >& rInitArgs = m_pImpl->m_aInitArgs;

			if ( rInitArgs.getLength() > 0 )
			{
				// Extract config provider from service init args.
				rInitArgs[ 0 ] >>= m_pImpl->m_xConfigProvider;

				OSL_ENSURE( m_pImpl->m_xConfigProvider.is(),
							"PropertySetRegistry::getConfigProvider - "
							"No config provider!" );
			}
			else
			{
				try
				{
					m_pImpl->m_xConfigProvider
						= Reference< XMultiServiceFactory >(
							m_xSMgr->createInstance(
								OUString::createFromAscii(
									"com.sun.star.configuration."
									"ConfigurationProvider" ) ),
							UNO_QUERY );

					OSL_ENSURE( m_pImpl->m_xConfigProvider.is(),
								"PropertySetRegistry::getConfigProvider - "
								"No config provider!" );

				}
				catch ( Exception& )
				{
					OSL_ENSURE( sal_False,
								"PropertySetRegistry::getConfigProvider - "
								"caught exception!" );
				}
			}
		}
	}

	return m_pImpl->m_xConfigProvider;
}

//=========================================================================
Reference< XInterface > PropertySetRegistry::getRootConfigReadAccess()
{
	try
	{
		osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

		if ( !m_pImpl->m_xRootReadAccess.is() )
		{
			if ( m_pImpl->m_bTriedToGetRootReadAccess ) // #82494#
			{
				OSL_ENSURE( sal_False,
							"PropertySetRegistry::getRootConfigReadAccess - "
							"Unable to read any config data! -> #82494#" );
				return Reference< XInterface >();
			}

			getConfigProvider();

			if ( m_pImpl->m_xConfigProvider.is() )
			{
				Sequence< Any > aArguments( 1 );
                PropertyValue aProperty;
                aProperty.Name
                    = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
                                            CFGPROPERTY_NODEPATH ) );
                aProperty.Value
                    <<= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
                                            STORE_CONTENTPROPERTIES_KEY ) );
                aArguments[ 0 ] <<= aProperty;

				m_pImpl->m_bTriedToGetRootReadAccess = sal_True;

				m_pImpl->m_xRootReadAccess =
					m_pImpl->m_xConfigProvider->createInstanceWithArguments(
						OUString::createFromAscii(
							"com.sun.star.configuration.ConfigurationAccess" ),
						aArguments );

				if ( m_pImpl->m_xRootReadAccess.is() )
					return m_pImpl->m_xRootReadAccess;
			}
		}
		else
			return m_pImpl->m_xRootReadAccess;
	}
	catch ( RuntimeException& )
	{
		throw;
	}
	catch ( Exception& )
	{
		// createInstance, createInstanceWithArguments

		OSL_ENSURE( sal_False,
			"PropertySetRegistry::getRootConfigReadAccess - caught Exception!" );
		return Reference< XInterface >();
	}

	OSL_ENSURE( sal_False,
				"PropertySetRegistry::getRootConfigReadAccess - Error!" );
	return Reference< XInterface >();
}

//=========================================================================
Reference< XInterface > PropertySetRegistry::getConfigWriteAccess(
													const OUString& rPath )
{
	try
	{
		osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

		if ( !m_pImpl->m_xRootWriteAccess.is() )
		{
			if ( m_pImpl->m_bTriedToGetRootWriteAccess ) // #82494#
			{
				OSL_ENSURE( sal_False,
							"PropertySetRegistry::getConfigWriteAccess - "
							"Unable to write any config data! -> #82494#" );
				return Reference< XInterface >();
			}

			getConfigProvider();

			if ( m_pImpl->m_xConfigProvider.is() )
			{
				Sequence< Any > aArguments( 2 );
				PropertyValue	aProperty;

				aProperty.Name
					= OUString( RTL_CONSTASCII_USTRINGPARAM(
											CFGPROPERTY_NODEPATH ) );
				aProperty.Value
					<<= OUString( RTL_CONSTASCII_USTRINGPARAM(
											STORE_CONTENTPROPERTIES_KEY ) );
				aArguments[ 0 ]	<<= aProperty;

				aProperty.Name
					= OUString(	RTL_CONSTASCII_USTRINGPARAM(
											CFGPROPERTY_LAZYWRITE ) );
				aProperty.Value	<<= sal_True;
				aArguments[ 1 ]	<<= aProperty;

				m_pImpl->m_bTriedToGetRootWriteAccess = sal_True;

				m_pImpl->m_xRootWriteAccess =
					m_pImpl->m_xConfigProvider->createInstanceWithArguments(
						OUString::createFromAscii(
							"com.sun.star.configuration.ConfigurationUpdateAccess" ),
						aArguments );

				OSL_ENSURE( m_pImpl->m_xRootWriteAccess.is(),
							"PropertySetRegistry::getConfigWriteAccess - "
							"No config update access!" );
			}
		}

		if ( m_pImpl->m_xRootWriteAccess.is() )
		{
			if ( rPath.getLength() )
			{
				Reference< XHierarchicalNameAccess > xNA(
								m_pImpl->m_xRootWriteAccess, UNO_QUERY );
				if ( xNA.is() )
				{
					Reference< XInterface > xInterface;
					xNA->getByHierarchicalName( rPath )	>>= xInterface;

					if ( xInterface.is() )
						return xInterface;
				}
			}
			else
				return m_pImpl->m_xRootWriteAccess;
		}
	}
	catch ( RuntimeException& )
	{
		throw;
	}
	catch ( NoSuchElementException& )
	{
		// getByHierarchicalName

		OSL_ENSURE( sal_False,
			"PropertySetRegistry::getConfigWriteAccess - "
			"caught NoSuchElementException!" );
		return Reference< XInterface >();
	}
	catch ( Exception& )
	{
		// createInstance, createInstanceWithArguments

		OSL_ENSURE( sal_False,
					"PropertySetRegistry::getConfigWriteAccess - "
					"caught Exception!" );
		return Reference< XInterface >();
	}

	OSL_ENSURE( sal_False,
				"PropertySetRegistry::getConfigWriteAccess - Error!" );
	return Reference< XInterface >();
}

//=========================================================================
//
// PropertyListeners_Impl.
//
//=========================================================================

typedef OMultiTypeInterfaceContainerHelperVar
<
	OUString,
	hashString_Impl,
	equalString_Impl
> PropertyListeners_Impl;

//=========================================================================
//
// PersistentPropertySet_Impl.
//
//=========================================================================

struct PersistentPropertySet_Impl
{
	PropertySetRegistry* 		m_pCreator;
	PropertySetInfo_Impl*		m_pInfo;
	OUString			 		m_aKey;
	OUString			 		m_aFullKey;
	osl::Mutex       			m_aMutex;
	OInterfaceContainerHelper*	m_pDisposeEventListeners;
	OInterfaceContainerHelper*  m_pPropSetChangeListeners;
	PropertyListeners_Impl*		m_pPropertyChangeListeners;

	PersistentPropertySet_Impl( PropertySetRegistry& rCreator,
								const OUString& rKey )
	: m_pCreator( &rCreator ), m_pInfo( NULL ), m_aKey( rKey ),
	  m_pDisposeEventListeners( NULL ), m_pPropSetChangeListeners( NULL ),
	  m_pPropertyChangeListeners( NULL )
	{
		m_pCreator->acquire();
	}

	~PersistentPropertySet_Impl()
	{
		m_pCreator->release();

		if ( m_pInfo )
			m_pInfo->release();

		delete m_pDisposeEventListeners;
		delete m_pPropSetChangeListeners;
		delete m_pPropertyChangeListeners;
	}
};

//=========================================================================
//=========================================================================
//=========================================================================
//
// PersistentPropertySet Implementation.
//
//=========================================================================
//=========================================================================
//=========================================================================

PersistentPropertySet::PersistentPropertySet(
						const Reference< XMultiServiceFactory >& rXSMgr,
						PropertySetRegistry& rCreator,
						const OUString& rKey )
: m_xSMgr( rXSMgr ),
  m_pImpl( new PersistentPropertySet_Impl( rCreator, rKey ) )
{
	// register at creator.
	rCreator.add( this );
}

//=========================================================================
// virtual
PersistentPropertySet::~PersistentPropertySet()
{
	// deregister at creator.
	m_pImpl->m_pCreator->remove( this );

	delete m_pImpl;
}

//=========================================================================
//
// XInterface methods.
//
//=========================================================================

XINTERFACE_IMPL_9( PersistentPropertySet,
				   XTypeProvider,
				   XServiceInfo,
				   XComponent,
				   XPropertySet, /* base of XPersistentPropertySet */
				   XNamed,
				   XPersistentPropertySet,
				   XPropertyContainer,
				   XPropertySetInfoChangeNotifier,
				   XPropertyAccess );

//=========================================================================
//
// XTypeProvider methods.
//
//=========================================================================

XTYPEPROVIDER_IMPL_8( PersistentPropertySet,
				   	  XTypeProvider,
				   	  XServiceInfo,
					  XComponent,
					  XPersistentPropertySet,
					  XNamed,
					  XPropertyContainer,
					  XPropertySetInfoChangeNotifier,
					  XPropertyAccess );

//=========================================================================
//
// XServiceInfo methods.
//
//=========================================================================

XSERVICEINFO_NOFACTORY_IMPL_1( PersistentPropertySet,
					 		   OUString::createFromAscii(
							   	"com.sun.star.comp.ucb.PersistentPropertySet" ),
					 		   OUString::createFromAscii(
							   	PERS_PROPSET_SERVICE_NAME ) );

//=========================================================================
//
// XComponent methods.
//
//=========================================================================

// virtual
void SAL_CALL PersistentPropertySet::dispose()
	throw( RuntimeException )
{
	if ( m_pImpl->m_pDisposeEventListeners &&
	     m_pImpl->m_pDisposeEventListeners->getLength() )
	{
		EventObject aEvt;
		aEvt.Source = static_cast< XComponent * >( this  );
		m_pImpl->m_pDisposeEventListeners->disposeAndClear( aEvt );
	}

	if ( m_pImpl->m_pPropSetChangeListeners &&
	     m_pImpl->m_pPropSetChangeListeners->getLength() )
	{
		EventObject aEvt;
		aEvt.Source = static_cast< XPropertySetInfoChangeNotifier * >( this  );
		m_pImpl->m_pPropSetChangeListeners->disposeAndClear( aEvt );
	}

	if ( m_pImpl->m_pPropertyChangeListeners )
	{
		EventObject aEvt;
		aEvt.Source = static_cast< XPropertySet * >( this  );
		m_pImpl->m_pPropertyChangeListeners->disposeAndClear( aEvt );
	}
}

//=========================================================================
// virtual
void SAL_CALL PersistentPropertySet::addEventListener(
							const Reference< XEventListener >& Listener )
	throw( RuntimeException )
{
	if ( !m_pImpl->m_pDisposeEventListeners )
		m_pImpl->m_pDisposeEventListeners =
					new OInterfaceContainerHelper( m_pImpl->m_aMutex );

	m_pImpl->m_pDisposeEventListeners->addInterface( Listener );
}

//=========================================================================
// virtual
void SAL_CALL PersistentPropertySet::removeEventListener(
							const Reference< XEventListener >& Listener )
	throw( RuntimeException )
{
	if ( m_pImpl->m_pDisposeEventListeners )
		m_pImpl->m_pDisposeEventListeners->removeInterface( Listener );

	// Note: Don't want to delete empty container here -> performance.
}

//=========================================================================
//
// XPropertySet methods.
//
//=========================================================================

// virtual
Reference< XPropertySetInfo > SAL_CALL
								PersistentPropertySet::getPropertySetInfo()
	throw( RuntimeException )
{
	osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

	PropertySetInfo_Impl*& rpInfo = m_pImpl->m_pInfo;
	if ( !rpInfo )
	{
		rpInfo = new PropertySetInfo_Impl( m_xSMgr, this );
		rpInfo->acquire();
	}
	return Reference< XPropertySetInfo >( rpInfo );
}

//=========================================================================
// virtual
void SAL_CALL PersistentPropertySet::setPropertyValue(
						const OUString& aPropertyName, const Any& aValue )
	throw( UnknownPropertyException,
		   PropertyVetoException,
		   IllegalArgumentException,
		   WrappedTargetException,
		   RuntimeException )
{
	if ( !aPropertyName.getLength() )
		throw UnknownPropertyException();

	osl::ClearableGuard< osl::Mutex > aCGuard( m_pImpl->m_aMutex );

	Reference< XHierarchicalNameAccess > xRootHierNameAccess(
				m_pImpl->m_pCreator->getRootConfigReadAccess(), UNO_QUERY );
	if ( xRootHierNameAccess.is() )
	{
		OUString aFullPropName( getFullKey() );
		aFullPropName += OUString::createFromAscii( "/" );
        aFullPropName += makeHierarchalNameSegment( aPropertyName );

		// Does property exist?
		if ( xRootHierNameAccess->hasByHierarchicalName( aFullPropName ) )
		{
			Reference< XNameReplace > xNameReplace(
					m_pImpl->m_pCreator->getConfigWriteAccess(
											aFullPropName ), UNO_QUERY );
			Reference< XChangesBatch > xBatch(
					m_pImpl->m_pCreator->getConfigWriteAccess(
											OUString() ), UNO_QUERY );

			if ( xNameReplace.is() && xBatch.is() )
			{
				try
				{
					// Obtain old value
					OUString aValueName = aFullPropName;
					aValueName += OUString::createFromAscii( "/Value" );
					Any aOldValue
						= xRootHierNameAccess->getByHierarchicalName(
																aValueName );
					// Check value type.
					if ( aOldValue.getValueType() != aValue.getValueType() )
					{
						aCGuard.clear();
						throw IllegalArgumentException();
					}

					// Write value
					xNameReplace->replaceByName(
									OUString::createFromAscii( "Value" ),
									aValue );

					// Write state ( Now it is a directly set value )
					xNameReplace->replaceByName(
									OUString::createFromAscii( "State" ),
									makeAny(
                                        sal_Int32(
                                            PropertyState_DIRECT_VALUE ) ) );

					// Commit changes.
					xBatch->commitChanges();

					PropertyChangeEvent aEvt;
					if ( m_pImpl->m_pPropertyChangeListeners )
					{
						// Obtain handle
						aValueName = aFullPropName;
						aValueName += OUString::createFromAscii( "/Handle" );
						sal_Int32 nHandle = -1;
						xRootHierNameAccess->getByHierarchicalName(	aValueName )
							>>= nHandle;

						aEvt.Source 	    = (OWeakObject*)this;
						aEvt.PropertyName   = aPropertyName;
						aEvt.PropertyHandle = nHandle;
						aEvt.Further        = sal_False;
						aEvt.OldValue       = aOldValue;
						aEvt.NewValue       = aValue;

						// Callback follows!
						aCGuard.clear();

						notifyPropertyChangeEvent( aEvt );
					}
					return;
				}
				catch ( IllegalArgumentException& )
				{
					// replaceByName
				}
				catch ( NoSuchElementException& )
				{
					// getByHierarchicalName, replaceByName
				}
				catch ( WrappedTargetException& )
				{
					// replaceByName, commitChanges
				}
			}
		}
	}

	throw UnknownPropertyException();
}

//=========================================================================
// virtual
Any SAL_CALL PersistentPropertySet::getPropertyValue(
											const OUString& PropertyName )
	throw( UnknownPropertyException,
		   WrappedTargetException,
		   RuntimeException )
{
	if ( !PropertyName.getLength() )
		throw UnknownPropertyException();

	osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

	Reference< XHierarchicalNameAccess > xNameAccess(
				m_pImpl->m_pCreator->getRootConfigReadAccess(), UNO_QUERY );
	if ( xNameAccess.is() )
	{
		OUString aFullPropName( getFullKey() );
		aFullPropName += OUString::createFromAscii( "/" );
        aFullPropName += makeHierarchalNameSegment( PropertyName );
        aFullPropName += OUString::createFromAscii( "/Value" );
		try
		{
			return xNameAccess->getByHierarchicalName( aFullPropName );
		}
		catch ( NoSuchElementException& )
		{
			throw UnknownPropertyException();
		}
	}

	throw UnknownPropertyException();
}

//=========================================================================
// virtual
void SAL_CALL PersistentPropertySet::addPropertyChangeListener(
					const OUString& aPropertyName,
					const Reference< XPropertyChangeListener >& xListener )
	throw( UnknownPropertyException,
		   WrappedTargetException,
		   RuntimeException )
{
//	load();

	if ( !m_pImpl->m_pPropertyChangeListeners )
		m_pImpl->m_pPropertyChangeListeners =
					new PropertyListeners_Impl( m_pImpl->m_aMutex );

	m_pImpl->m_pPropertyChangeListeners->addInterface(
												aPropertyName, xListener );
}

//=========================================================================
// virtual
void SAL_CALL PersistentPropertySet::removePropertyChangeListener(
					const OUString& aPropertyName,
					const Reference< XPropertyChangeListener >& aListener )
	throw( UnknownPropertyException,
		   WrappedTargetException,
		   RuntimeException )
{
//	load();

	if ( m_pImpl->m_pPropertyChangeListeners )
		m_pImpl->m_pPropertyChangeListeners->removeInterface(
												aPropertyName, aListener );

	// Note: Don't want to delete empty container here -> performance.
}

//=========================================================================
// virtual
void SAL_CALL PersistentPropertySet::addVetoableChangeListener(
					const OUString&,
					const Reference< XVetoableChangeListener >& )
	throw( UnknownPropertyException,
		   WrappedTargetException,
		   RuntimeException )
{
//	load();
//	OSL_ENSURE( sal_False,
//				"PersistentPropertySet::addVetoableChangeListener - N.Y.I." );
}

//=========================================================================
// virtual
void SAL_CALL PersistentPropertySet::removeVetoableChangeListener(
					const OUString&,
					const Reference< XVetoableChangeListener >& )
	throw( UnknownPropertyException,
		   WrappedTargetException,
		   RuntimeException )
{
//	load();
//	OSL_ENSURE( sal_False,
//				"PersistentPropertySet::removeVetoableChangeListener - N.Y.I." );
}

//=========================================================================
//
// XPersistentPropertySet methods.
//
//=========================================================================

// virtual
Reference< XPropertySetRegistry > SAL_CALL PersistentPropertySet::getRegistry()
	throw( RuntimeException )
{
	return Reference< XPropertySetRegistry >( m_pImpl->m_pCreator );
}

//=========================================================================
// virtual
OUString SAL_CALL PersistentPropertySet::getKey()
	throw( RuntimeException )
{
	return m_pImpl->m_aKey;
}

//=========================================================================
//
// XNamed methods.
//
//=========================================================================

// virtual
rtl::OUString SAL_CALL PersistentPropertySet::getName()
	throw( RuntimeException )
{
	// same as getKey()
	return m_pImpl->m_aKey;
}

//=========================================================================
// virtual
void SAL_CALL PersistentPropertySet::setName( const OUString& aName )
	throw( RuntimeException )
{
	if ( aName != m_pImpl->m_aKey )
		m_pImpl->m_pCreator->renamePropertySet( m_pImpl->m_aKey, aName );
}

//=========================================================================
//
// XPropertyContainer methods.
//
//=========================================================================

// virtual
void SAL_CALL PersistentPropertySet::addProperty(
		const OUString& Name, sal_Int16 Attributes, const Any& DefaultValue )
	throw( PropertyExistException,
		   IllegalTypeException,
		   IllegalArgumentException,
		   RuntimeException )
{
	if ( !Name.getLength() )
		throw IllegalArgumentException();

	// @@@ What other types can't be written to config server?

	// Check type class ( Not all types can be written to storage )
	TypeClass eTypeClass = DefaultValue.getValueTypeClass();
	if ( eTypeClass == TypeClass_INTERFACE )
		throw IllegalTypeException();

	osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

	// Property already in set?

	OUString aFullValuesName;

	Reference< XHierarchicalNameAccess > xRootHierNameAccess(
				m_pImpl->m_pCreator->getRootConfigReadAccess(), UNO_QUERY );
	if ( xRootHierNameAccess.is() )
	{
		aFullValuesName = getFullKey();
		OUString aFullPropName = aFullValuesName;
		aFullPropName += OUString::createFromAscii( "/" );
        aFullPropName += makeHierarchalNameSegment( Name );

		if ( xRootHierNameAccess->hasByHierarchicalName( aFullPropName ) )
		{
			// Already in set.
			throw PropertyExistException();
		}
	}

	// Property is always removeable.
	Attributes |= PropertyAttribute::REMOVEABLE;

	// Add property.

	Reference< XSingleServiceFactory > xFac(
				m_pImpl->m_pCreator->getConfigWriteAccess( aFullValuesName ),
				UNO_QUERY );
	Reference< XNameContainer > xContainer( xFac, UNO_QUERY );
	Reference< XChangesBatch >  xBatch(
				m_pImpl->m_pCreator->getConfigWriteAccess( OUString() ),
				UNO_QUERY );

	OSL_ENSURE( xFac.is(),
				"PersistentPropertySet::addProperty - No factory!" );

	OSL_ENSURE( xBatch.is(),
				"PersistentPropertySet::addProperty - No batch!" );

	OSL_ENSURE( xContainer.is(),
				"PersistentPropertySet::addProperty - No container!" );

	if ( xFac.is() && xBatch.is() && xContainer.is() )
	{
		try
		{
			// Create new "PropertyValue" config item.
			Reference< XNameReplace > xNameReplace(
										xFac->createInstance(), UNO_QUERY );

			if ( xNameReplace.is() )
			{
				// Fill new item...

				// Set handle
				xNameReplace->replaceByName(
									OUString::createFromAscii( "Handle" ),
									makeAny( sal_Int32( -1 ) ) );

				// Set default value
				xNameReplace->replaceByName(
									OUString::createFromAscii( "Value" ),
									DefaultValue );

				// Set state ( always "default" )
				xNameReplace->replaceByName(
									OUString::createFromAscii( "State" ),
									makeAny(
                                        sal_Int32(
                                            PropertyState_DEFAULT_VALUE ) ) );

				// Set attributes
				xNameReplace->replaceByName(
									OUString::createFromAscii( "Attributes" ),
									makeAny( sal_Int32( Attributes ) ) );

				// Insert new item.
				xContainer->insertByName( Name, makeAny( xNameReplace ) );

				// Commit changes.
				xBatch->commitChanges();

				// Property set info is invalid.
				if ( m_pImpl->m_pInfo )
					m_pImpl->m_pInfo->reset();

				// Notify propertyset info change listeners.
				if ( m_pImpl->m_pPropSetChangeListeners &&
			 		m_pImpl->m_pPropSetChangeListeners->getLength() )
				{
					PropertySetInfoChangeEvent evt(
									static_cast< OWeakObject * >( this ),
									Name,
									-1,
									PropertySetInfoChange::PROPERTY_INSERTED );
					notifyPropertySetInfoChange( evt );
				}

				// Success.
				return;
			}
		}
		catch ( IllegalArgumentException& )
		{
			// insertByName

			OSL_ENSURE( sal_False,
						"PersistentPropertySet::addProperty - "
						"caught IllegalArgumentException!" );
			return;
		}
		catch ( ElementExistException& )
		{
			// insertByName

			OSL_ENSURE( sal_False,
						"PersistentPropertySet::addProperty - "
						"caught ElementExistException!" );
			return;
		}
		catch ( WrappedTargetException& )
		{
			// replaceByName, insertByName, commitChanges

			OSL_ENSURE( sal_False,
						"PersistentPropertySet::addProperty - "
						"caught WrappedTargetException!" );
			return;
		}
		catch ( RuntimeException& )
		{
			throw;
		}
		catch ( Exception& )
		{
			// createInstance

			OSL_ENSURE( sal_False,
						"PersistentPropertySet::addProperty - "
						"caught Exception!" );
			return;
		}
	}

	OSL_ENSURE( sal_False,
				"PersistentPropertySet::addProperty - Error!" );
}

//=========================================================================
// virtual
void SAL_CALL PersistentPropertySet::removeProperty( const OUString& Name )
	throw( UnknownPropertyException,
		   NotRemoveableException,
		   RuntimeException )
{
	osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

	OUString aFullValuesName;
	OUString aFullPropName;

	Reference< XHierarchicalNameAccess > xRootHierNameAccess(
				m_pImpl->m_pCreator->getRootConfigReadAccess(), UNO_QUERY );
	if ( xRootHierNameAccess.is() )
	{
		aFullValuesName = getFullKey();
		aFullPropName   = aFullValuesName;
        aFullPropName   += OUString::createFromAscii( "/" );
        aFullPropName   += makeHierarchalNameSegment( Name );

		// Property in set?
		if ( !xRootHierNameAccess->hasByHierarchicalName( aFullPropName ) )
			throw UnknownPropertyException();

		// Property removeable?
		try
		{
			OUString aFullAttrName = aFullPropName;
			aFullAttrName += OUString::createFromAscii( "/Attributes" );

			sal_Int32 nAttribs = 0;
			if ( xRootHierNameAccess->getByHierarchicalName( aFullAttrName )
					>>= nAttribs )
			{
				if ( !( nAttribs & PropertyAttribute::REMOVEABLE ) )
				{
					// Not removeable!
					throw NotRemoveableException();
				}
			}
			else
			{
				OSL_ENSURE( sal_False,
							"PersistentPropertySet::removeProperty - "
							"No attributes!" );
				return;
			}
		}
		catch ( NoSuchElementException& )
		{
			// getByHierarchicalName

			OSL_ENSURE( sal_False,
						"PersistentPropertySet::removeProperty - "
						"caught NoSuchElementException!" );
		}

		// Remove property...

		Reference< XNameContainer > xContainer(
				m_pImpl->m_pCreator->getConfigWriteAccess( aFullValuesName ),
				UNO_QUERY );
		Reference< XChangesBatch > xBatch(
				m_pImpl->m_pCreator->getConfigWriteAccess( OUString() ),
				UNO_QUERY );

		OSL_ENSURE( xBatch.is(),
					"PersistentPropertySet::removeProperty - No batch!" );

		OSL_ENSURE( xContainer.is(),
					"PersistentPropertySet::removeProperty - No container!" );

		if ( xBatch.is() && xContainer.is() )
		{
			try
			{
				sal_Int32 nHandle = -1;

				if ( m_pImpl->m_pPropSetChangeListeners &&
	 		 		 m_pImpl->m_pPropSetChangeListeners->getLength() )
				{
					// Obtain property handle ( needed for propertysetinfo
					// change event )...

					try
					{
						OUString aFullHandleName = aFullPropName;
						aFullHandleName
								+= OUString::createFromAscii( "/Handle" );

						if ( ! ( xRootHierNameAccess->getByHierarchicalName(
										aFullHandleName ) >>= nHandle ) )
							nHandle = -1;

					}
					catch ( NoSuchElementException& )
					{
						// getByHierarchicalName

						OSL_ENSURE( sal_False,
									"PersistentPropertySet::removeProperty - "
									"caught NoSuchElementException!" );
						nHandle = -1;
					}
				}

				xContainer->removeByName( Name );
				xBatch->commitChanges();

				// Property set info is invalid.
				if ( m_pImpl->m_pInfo )
					m_pImpl->m_pInfo->reset();

				// Notify propertyset info change listeners.
				if ( m_pImpl->m_pPropSetChangeListeners &&
	 		 		m_pImpl->m_pPropSetChangeListeners->getLength() )
				{
					PropertySetInfoChangeEvent evt(
									static_cast< OWeakObject * >( this ),
									Name,
									nHandle,
									PropertySetInfoChange::PROPERTY_REMOVED );
					notifyPropertySetInfoChange( evt );
				}

				// Success.
				return;
			}
			catch ( NoSuchElementException& )
			{
				// removeByName

				OSL_ENSURE( sal_False,
							"PersistentPropertySet::removeProperty - "
							"caught NoSuchElementException!" );
				return;
			}
			catch ( WrappedTargetException& )
			{
				// commitChanges

				OSL_ENSURE( sal_False,
							"PersistentPropertySet::removeProperty - "
							"caught WrappedTargetException!" );
				return;
			}
		}
	}

	OSL_ENSURE( sal_False,
				"PersistentPropertySet::removeProperty - Error!" );
}

//=========================================================================
//
// XPropertySetInfoChangeNotifier methods.
//
//=========================================================================

// virtual
void SAL_CALL PersistentPropertySet::addPropertySetInfoChangeListener(
				const Reference< XPropertySetInfoChangeListener >& Listener )
	throw( RuntimeException )
{
	if ( !m_pImpl->m_pPropSetChangeListeners )
		m_pImpl->m_pPropSetChangeListeners =
					new OInterfaceContainerHelper( m_pImpl->m_aMutex );

	m_pImpl->m_pPropSetChangeListeners->addInterface( Listener );
}

//=========================================================================
// virtual
void SAL_CALL PersistentPropertySet::removePropertySetInfoChangeListener(
				const Reference< XPropertySetInfoChangeListener >& Listener )
	throw( RuntimeException )
{
	if ( m_pImpl->m_pPropSetChangeListeners )
		m_pImpl->m_pPropSetChangeListeners->removeInterface( Listener );
}

//=========================================================================
//
// XPropertyAccess methods.
//
//=========================================================================

// virtual
Sequence< PropertyValue > SAL_CALL PersistentPropertySet::getPropertyValues()
	throw( RuntimeException )
{
	osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

	Reference< XHierarchicalNameAccess > xRootHierNameAccess(
				m_pImpl->m_pCreator->getRootConfigReadAccess(), UNO_QUERY );
	if ( xRootHierNameAccess.is() )
	{
		try
		{
			Reference< XNameAccess > xNameAccess;
			xRootHierNameAccess->getByHierarchicalName(getFullKey())
                >>= xNameAccess;
			if ( xNameAccess.is() )
			{
				// Obtain property names.

				Sequence< OUString > aElems = xNameAccess->getElementNames();

				sal_Int32 nCount = aElems.getLength();
				if ( nCount )
				{
					Reference< XHierarchicalNameAccess > xHierNameAccess(
													xNameAccess, UNO_QUERY );

					OSL_ENSURE( xHierNameAccess.is(),
								"PersistentPropertySet::getPropertyValues - "
								"No hierarchical name access!" );

					if ( xHierNameAccess.is() )
					{
						Sequence< PropertyValue > aValues( nCount );

                        const OUString aHandleName
									= OUString::createFromAscii( "/Handle" );
                        const OUString aValueName
									= OUString::createFromAscii( "/Value" );
                        const OUString aStateName
									= OUString::createFromAscii( "/State" );

						for ( sal_Int32 n = 0; n < nCount; ++n )
						{
							PropertyValue& rValue = aValues[ n ];
                            OUString rName    = aElems[ n ];
                            OUString aXMLName
                                        = makeHierarchalNameSegment( rName );

							// Set property name.

							rValue.Name = rName;

							try
							{
								// Obtain and set property handle
                                OUString aHierName = aXMLName;
								aHierName += aHandleName;
								Any aKeyValue
									= xHierNameAccess->getByHierarchicalName(
										aHierName );

								if ( !( aKeyValue >>= rValue.Handle ) )
									OSL_ENSURE( sal_False,
									  "PersistentPropertySet::getPropertyValues - "
									  "Error getting property handle!" );
							}
							catch ( NoSuchElementException& )
							{
								// getByHierarchicalName

								OSL_ENSURE( sal_False,
								  "PersistentPropertySet::getPropertyValues - "
								  "NoSuchElementException!" );
							}

							try
							{
								// Obtain and set property value
                                OUString aHierName = aXMLName;
								aHierName += aValueName;
								rValue.Value
									= xHierNameAccess->getByHierarchicalName(
										aHierName );

								// Note: The value may be void if addProperty
								//       was called with a default value
								//       of type void.
							}
							catch ( NoSuchElementException& )
							{
								// getByHierarchicalName

								OSL_ENSURE( sal_False,
								  "PersistentPropertySet::getPropertyValues - "
								  "NoSuchElementException!" );
							}

							try
							{
								// Obtain and set property state
                                OUString aHierName = aXMLName;
								aHierName += aStateName;
								Any aKeyValue
									= xHierNameAccess->getByHierarchicalName(
										aHierName );

								sal_Int32 nState = 0;
								if ( !( aKeyValue >>= nState ) )
									OSL_ENSURE( sal_False,
									  "PersistentPropertySet::getPropertyValues - "
									  "Error getting property state!" );
								else
									rValue.State = PropertyState( nState );
							}
							catch ( NoSuchElementException& )
							{
								// getByHierarchicalName

								OSL_ENSURE( sal_False,
								  "PersistentPropertySet::getPropertyValues - "
								  "NoSuchElementException!" );
							}
						}

						return aValues;
					}
				}
			}
		}
		catch ( NoSuchElementException& )
		{
			// getByHierarchicalName
		}
	}

	return Sequence< PropertyValue >( 0 );
}

//=========================================================================
// virtual
void SAL_CALL PersistentPropertySet::setPropertyValues(
 								const Sequence< PropertyValue >& aProps )
	throw( UnknownPropertyException,
		   PropertyVetoException,
		   IllegalArgumentException,
		   WrappedTargetException,
		   RuntimeException )
{
	sal_Int32 nCount = aProps.getLength();
	if ( !nCount )
		return;

	osl::ClearableGuard< osl::Mutex > aCGuard( m_pImpl->m_aMutex );

	Reference< XHierarchicalNameAccess > xRootHierNameAccess(
				m_pImpl->m_pCreator->getRootConfigReadAccess(), UNO_QUERY );
	if ( xRootHierNameAccess.is() )
	{
		const PropertyValue* pNewValues = aProps.getConstArray();

		typedef std::list< PropertyChangeEvent > Events;
		Events aEvents;

		OUString aFullPropNamePrefix( getFullKey() );
		aFullPropNamePrefix += OUString::createFromAscii( "/" );

		// Iterate over given property value sequence.
		for ( sal_Int32 n = 0; n < nCount; ++n )
		{
			const PropertyValue& rNewValue = pNewValues[ n ];
			const OUString& rName = rNewValue.Name;

			OUString aFullPropName = aFullPropNamePrefix;
            aFullPropName += makeHierarchalNameSegment( rName );

			// Does property exist?
			if ( xRootHierNameAccess->hasByHierarchicalName( aFullPropName ) )
			{
				Reference< XNameReplace > xNameReplace(
					m_pImpl->m_pCreator->getConfigWriteAccess(
											aFullPropName ), UNO_QUERY );
				Reference< XChangesBatch > xBatch(
					m_pImpl->m_pCreator->getConfigWriteAccess(
											OUString() ), UNO_QUERY );

				if ( xNameReplace.is() && xBatch.is() )
				{
					try
					{
						// Write handle
						xNameReplace->replaceByName(
									OUString::createFromAscii( "Handle" ),
									makeAny( rNewValue.Handle ) );

						// Save old value
						OUString aValueName = aFullPropName;
						aValueName += OUString::createFromAscii( "/Value" );
						Any aOldValue
							= xRootHierNameAccess->getByHierarchicalName(
																aValueName );
						// Write value
						xNameReplace->replaceByName(
									OUString::createFromAscii( "Value" ),
									rNewValue.Value );

						// Write state ( Now it is a directly set value )
						xNameReplace->replaceByName(
									OUString::createFromAscii( "State" ),
									makeAny(
                                        sal_Int32(
                                            PropertyState_DIRECT_VALUE ) ) );

						// Commit changes.
						xBatch->commitChanges();

						if ( m_pImpl->m_pPropertyChangeListeners )
						{
							PropertyChangeEvent aEvt;
							aEvt.Source 	    = (OWeakObject*)this;
							aEvt.PropertyName   = rNewValue.Name;
							aEvt.PropertyHandle = rNewValue.Handle;
							aEvt.Further        = sal_False;
							aEvt.OldValue       = aOldValue;
							aEvt.NewValue       = rNewValue.Value;

							aEvents.push_back( aEvt );
						}
					}
					catch ( IllegalArgumentException& )
					{
						// replaceByName
					}
					catch ( NoSuchElementException& )
					{
						// getByHierarchicalName, replaceByName
					}
					catch ( WrappedTargetException& )
					{
						// replaceByName, commitChanges
					}
				}
			}
		}

		// Callback follows!
		aCGuard.clear();

		if ( m_pImpl->m_pPropertyChangeListeners )
		{
			// Notify property changes.
			Events::const_iterator it  = aEvents.begin();
			Events::const_iterator end = aEvents.end();

			while ( it != end )
			{
				notifyPropertyChangeEvent( (*it) );
				it++;
			}
		}

		return;
	}

	OSL_ENSURE( sal_False,
				"PersistentPropertySet::setPropertyValues - Nothing set!" );
}

//=========================================================================
//
// Non-interface methods
//
//=========================================================================

void PersistentPropertySet::notifyPropertyChangeEvent(
									const PropertyChangeEvent& rEvent ) const
{
	// Get "normal" listeners for the property.
	OInterfaceContainerHelper* pContainer =
			m_pImpl->m_pPropertyChangeListeners->getContainer(
													rEvent.PropertyName );
	if ( pContainer && pContainer->getLength() )
	{
		OInterfaceIteratorHelper aIter( *pContainer );
		while ( aIter.hasMoreElements() )
		{
			// Propagate event.
			Reference< XPropertyChangeListener > xListener(
													aIter.next(), UNO_QUERY );
			if ( xListener.is() )
				xListener->propertyChange( rEvent );
		}
	}

	// Get "normal" listeners for all properties.
	OInterfaceContainerHelper* pNoNameContainer =
			m_pImpl->m_pPropertyChangeListeners->getContainer( OUString() );
	if ( pNoNameContainer && pNoNameContainer->getLength() )
	{
		OInterfaceIteratorHelper aIter( *pNoNameContainer );
		while ( aIter.hasMoreElements() )
		{
			// Propagate event.
			Reference< XPropertyChangeListener > xListener(
													aIter.next(), UNO_QUERY );
			if ( xListener.is() )
				xListener->propertyChange( rEvent );
		}
	}
}

//=========================================================================
void PersistentPropertySet::notifyPropertySetInfoChange(
								const PropertySetInfoChangeEvent& evt ) const
{
	if ( !m_pImpl->m_pPropSetChangeListeners )
		return;

	// Notify event listeners.
	OInterfaceIteratorHelper aIter( *( m_pImpl->m_pPropSetChangeListeners ) );
	while ( aIter.hasMoreElements() )
	{
		// Propagate event.
		Reference< XPropertySetInfoChangeListener >
							xListener( aIter.next(), UNO_QUERY );
		if ( xListener.is() )
			xListener->propertySetInfoChange( evt );
	}
}

//=========================================================================
const OUString& PersistentPropertySet::getFullKey()
{
	if ( !m_pImpl->m_aFullKey.getLength() )
	{
        osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
        if ( !m_pImpl->m_aFullKey.getLength() )
        {
            m_pImpl->m_aFullKey
                = makeHierarchalNameSegment( m_pImpl->m_aKey );
            m_pImpl->m_aFullKey
                += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/Values" ) );
        }
	}

	return m_pImpl->m_aFullKey;
}

//=========================================================================
PropertySetRegistry& PersistentPropertySet::getPropertySetRegistry()
{
	return *m_pImpl->m_pCreator;
}

//=========================================================================
//=========================================================================
//
// PropertySetInfo_Impl Implementation.
//
//=========================================================================
//=========================================================================

PropertySetInfo_Impl::PropertySetInfo_Impl(
						const Reference< XMultiServiceFactory >& rxSMgr,
						PersistentPropertySet* pOwner )
: m_xSMgr( rxSMgr ),
  m_pProps( NULL ),
  m_pOwner( pOwner )
{
}

//=========================================================================
// virtual
PropertySetInfo_Impl::~PropertySetInfo_Impl()
{
	delete m_pProps;

	// !!! Do not delete m_pOwner !!!
}

//=========================================================================
//
// XInterface methods.
//
//=========================================================================

XINTERFACE_IMPL_2( PropertySetInfo_Impl,
				   XTypeProvider,
				   XPropertySetInfo );

//=========================================================================
//
// XTypeProvider methods.
//
//=========================================================================

XTYPEPROVIDER_IMPL_2( PropertySetInfo_Impl,
				   	  XTypeProvider,
				   	  XPropertySetInfo );

//=========================================================================
//
// XPropertySetInfo methods.
//
//=========================================================================

// virtual
Sequence< Property > SAL_CALL PropertySetInfo_Impl::getProperties()
	throw( RuntimeException )
{
	if ( !m_pProps )
	{
		Reference< XHierarchicalNameAccess > xRootHierNameAccess(
			m_pOwner->getPropertySetRegistry().getRootConfigReadAccess(),
			UNO_QUERY );
		if ( xRootHierNameAccess.is() )
		{
			try
			{
				Reference< XNameAccess > xNameAccess;
				xRootHierNameAccess->getByHierarchicalName(
							m_pOwner->getFullKey() )
					>>= xNameAccess;
				if ( xNameAccess.is() )
				{
					// Obtain property names.

					Sequence< OUString > aElems
											= xNameAccess->getElementNames();

					sal_uInt32 nCount = aElems.getLength();
					Sequence< Property >* pPropSeq
										= new Sequence< Property >( nCount );

					if ( nCount )
					{
						Reference< XHierarchicalNameAccess > xHierNameAccess(
													xNameAccess, UNO_QUERY );

						OSL_ENSURE( xHierNameAccess.is(),
									"PropertySetInfo_Impl::getProperties - "
									"No hierarchical name access!" );

						if ( xHierNameAccess.is() )
						{
                            const OUString aHandleName
								= OUString::createFromAscii( "/Handle" );
                            const OUString aValueName
								= OUString::createFromAscii( "/Value" );
                            const OUString aAttrName
								= OUString::createFromAscii( "/Attributes" );

							Property* pProps = pPropSeq->getArray();

							for ( sal_uInt32 n = 0; n < nCount; ++n )
							{
								Property& rProp = pProps[ n ];
                                OUString  rName = aElems[ n ];
                                OUString aXMLName
                                    = makeHierarchalNameSegment( rName );

								// Set property name.

								rProp.Name = rName;

								try
								{
									// Obtain and set property handle
                                    rtl::OUString aHierName = aXMLName;
									aHierName += aHandleName;
									Any aKeyValue
										= xHierNameAccess->getByHierarchicalName(
											aHierName );

									if ( !( aKeyValue >>= rProp.Handle ) )
										OSL_ENSURE( sal_False,
									  	"PropertySetInfo_Impl::getProperties - "
									  	"Error getting property handle!" );
								}
								catch ( NoSuchElementException& )
								{
									// getByHierarchicalName

									OSL_ENSURE( sal_False,
								  	"PropertySetInfo_Impl::getProperties - "
								  	"NoSuchElementException!" );
								}

								try
								{
									// Obtain and set property type
                                    rtl::OUString aHierName = aXMLName;
									aHierName += aValueName;
									Any aKeyValue
										= xHierNameAccess->getByHierarchicalName(
											aHierName );

									// Note: The type may be void if addProperty
									//       was called with a default value
									//       of type void.

									rProp.Type = aKeyValue.getValueType();
								}
								catch ( NoSuchElementException& )
								{
									// getByHierarchicalName

									OSL_ENSURE( sal_False,
								  	"PropertySetInfo_Impl::getProperties - "
								  	"NoSuchElementException!" );
								}

								try
								{
									// Obtain and set property attributes
                                    rtl::OUString aHierName = aXMLName;
									aHierName += aAttrName;
									Any aKeyValue
										= xHierNameAccess->getByHierarchicalName(
											aHierName );

									sal_Int32 nAttribs = 0;
									if ( aKeyValue >>= nAttribs )
										rProp.Attributes
											= sal_Int16( nAttribs );
									else
										OSL_ENSURE( sal_False,
									  	"PropertySetInfo_Impl::getProperties - "
									  	"Error getting property attributes!" );
								}
								catch ( NoSuchElementException& )
								{
									// getByHierarchicalName

									OSL_ENSURE( sal_False,
								  	"PropertySetInfo_Impl::getProperties - "
								  	"NoSuchElementException!" );
								}
							}
						}
					}

					// Success.
					m_pProps = pPropSeq;
					return *m_pProps;
				}
			}
			catch ( NoSuchElementException& )
			{
				// getByHierarchicalName
			}
		}

		OSL_ENSURE( sal_False, "PropertySetInfo_Impl::getProperties - Error!" );
		m_pProps = new Sequence< Property >( 0 );
	}

	return *m_pProps;
}

//=========================================================================
// virtual
Property SAL_CALL PropertySetInfo_Impl::getPropertyByName(
													const OUString& aName )
	throw( UnknownPropertyException, RuntimeException )
{
	Reference< XHierarchicalNameAccess > xRootHierNameAccess(
			m_pOwner->getPropertySetRegistry().getRootConfigReadAccess(),
			UNO_QUERY );
	if ( xRootHierNameAccess.is() )
	{
		OUString aFullPropName( m_pOwner->getFullKey() );
		aFullPropName += OUString::createFromAscii( "/" );
        aFullPropName += makeHierarchalNameSegment( aName );

		// Does property exist?
		if ( !xRootHierNameAccess->hasByHierarchicalName( aFullPropName ) )
			throw UnknownPropertyException();

		try
		{
			Property aProp;

			// Obtain handle.
			OUString aKey = aFullPropName;
			aKey += OUString::createFromAscii( "/Handle" );

			if ( !( xRootHierNameAccess->getByHierarchicalName( aKey )
					>>= aProp.Handle ) )
			{
				OSL_ENSURE( sal_False,
							"PropertySetInfo_Impl::getPropertyByName - "
							"No handle!" );
				return Property();
			}

			// Obtain Value and extract type.
			aKey = aFullPropName;
			aKey += OUString::createFromAscii( "/Value" );

			Any aValue = xRootHierNameAccess->getByHierarchicalName( aKey );
			if ( !aValue.hasValue() )
			{
				OSL_ENSURE( sal_False,
							"PropertySetInfo_Impl::getPropertyByName - "
							"No Value!" );
				return Property();
			}

			aProp.Type = aValue.getValueType();

			// Obtain Attributes.
			aKey = aFullPropName;
			aKey += OUString::createFromAscii( "/Attributes" );

			sal_Int32 nAttribs = 0;
			if ( xRootHierNameAccess->getByHierarchicalName( aKey )
					>>= nAttribs )
				aProp.Attributes = sal_Int16( nAttribs );
			else
			{
				OSL_ENSURE( sal_False,
							"PropertySetInfo_Impl::getPropertyByName - "
							"No attributes!" );
				return Property();
			}

			// set name.
			aProp.Name = aName;

			// Success.
			return aProp;
		}
		catch ( NoSuchElementException& )
		{
			// getByHierarchicalName

			OSL_ENSURE( sal_False,
						"PropertySetInfo_Impl::getPropertyByName - "
						"caught NoSuchElementException!" );
		}

	}

	OSL_ENSURE( sal_False, "PropertySetInfo_Impl::getPropertyByName - Error!" );
	return Property();
}

//=========================================================================
// virtual
sal_Bool SAL_CALL PropertySetInfo_Impl::hasPropertyByName(
													const OUString& Name )
	throw( RuntimeException )
{
	Reference< XHierarchicalNameAccess > xRootHierNameAccess(
			m_pOwner->getPropertySetRegistry().getRootConfigReadAccess(),
			UNO_QUERY );
	if ( xRootHierNameAccess.is() )
	{
		OUString aFullPropName( m_pOwner->getFullKey() );
		aFullPropName += OUString::createFromAscii( "/" );
        aFullPropName += makeHierarchalNameSegment( Name );

		return xRootHierNameAccess->hasByHierarchicalName( aFullPropName );
	}

	return sal_False;
}

