    /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
    /*
     * This file is part of the LibreOffice project.
     *
     * This Source Code Form is subject to the terms of the Mozilla Public
     * License, v. 2.0. If a copy of the MPL was not distributed with this
     * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     *
     * This file incorporates work covered by the following license notice:
     *
     *   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 .
     */

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

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

    #include <memory>
    #include <list>
    #include <unordered_map>
    #include <sal/log.hxx>
    #include <osl/diagnose.h>
    #include <rtl/ustrbuf.hxx>
    #include <rtl/ref.hxx>
    #include <cppuhelper/interfacecontainer.hxx>
    #include <comphelper/interfacecontainer2.hxx>
    #include <comphelper/propertysequence.hxx>
    #include <com/sun/star/beans/IllegalTypeException.hpp>
    #include <com/sun/star/beans/NotRemoveableException.hpp>
    #include <com/sun/star/beans/PropertyAttribute.hpp>
    #include <com/sun/star/beans/PropertyExistException.hpp>
    #include <com/sun/star/beans/PropertySetInfoChange.hpp>
    #include <com/sun/star/configuration/theDefaultProvider.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 <com/sun/star/lang/XSingleServiceFactory.hpp>
    #include <comphelper/processfactory.hxx>
    #include <cppuhelper/implbase.hxx>
    #include <ucbhelper/getcomponentcontext.hxx>
    #include "ucbstore.hxx"

    using namespace com::sun::star::beans;
    using namespace com::sun::star::configuration;
    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 comphelper;
    using namespace cppu;

    OUString makeHierarchalNameSegment( const OUString & rIn  )
    {
        OUStringBuffer aBuffer;
        aBuffer.append( "['" );

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

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

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

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

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

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

        aBuffer.append( "']" );
        return aBuffer.makeStringAndClear();
    }

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

    // describe path of cfg entry
    #define CFGPROPERTY_NODEPATH        "nodepath"

    // PropertySetMap_Impl.
    typedef std::unordered_map< OUString, PersistentPropertySet*> PropertySetMap_Impl;

    // class PropertySetInfo_Impl
    class PropertySetInfo_Impl : public cppu::WeakImplHelper < XPropertySetInfo >
    {
        std::unique_ptr<Sequence< Property >>
                                          m_pProps;
        PersistentPropertySet*            m_pOwner;

    public:
        explicit PropertySetInfo_Impl(PersistentPropertySet* pOwner);

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

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

    // UcbStore_Impl.

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

    // UcbStore Implementation.

    UcbStore::UcbStore( const Reference< XComponentContext >& xContext )
    : m_xContext( xContext ),
      m_pImpl( new UcbStore_Impl )
    {
    }

    // virtual
    UcbStore::~UcbStore()
    {
    }

    XSERVICEINFO_COMMOM_IMPL( UcbStore,
                              OUString( "com.sun.star.comp.ucb.UcbStore" ) )
    /// @throws css::uno::Exception
    static css::uno::Reference< css::uno::XInterface >
    UcbStore_CreateInstance( const css::uno::Reference< css::lang::XMultiServiceFactory> & rSMgr )
    {
        css::lang::XServiceInfo* pX =
            static_cast<css::lang::XServiceInfo*>(new UcbStore( ucbhelper::getComponentContext(rSMgr) ));
        return css::uno::Reference< css::uno::XInterface >::query( pX );
    }

    css::uno::Sequence< OUString >
    UcbStore::getSupportedServiceNames_Static()
    {
        css::uno::Sequence< OUString > aSNS { STORE_SERVICE_NAME };
        return aSNS;
    }

    // Service factory implementation.

    ONE_INSTANCE_SERVICE_FACTORY_IMPL( UcbStore );

    // XPropertySetRegistryFactory methods.

    // virtual
    Reference< XPropertySetRegistry > SAL_CALL
    UcbStore::createPropertySetRegistry( const OUString& )
    {
        // 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_xContext, m_pImpl->m_aInitArgs );
        }

        return m_pImpl->m_xTheRegistry;
    }

    // XInitialization methods.

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

    // 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;
        bool                              m_bTriedToGetRootReadAccess;
        bool                              m_bTriedToGetRootWriteAccess;

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

    // PropertySetRegistry Implementation.

    PropertySetRegistry::PropertySetRegistry(
                            const Reference< XComponentContext >& xContext,
                            const Sequence< Any > &rInitArgs )
    : m_xContext( xContext ),
      m_pImpl( new PropertySetRegistry_Impl( rInitArgs ) )
    {
    }

    // virtual
    PropertySetRegistry::~PropertySetRegistry()
    {
    }

    // XServiceInfo methods.

    OUString SAL_CALL PropertySetRegistry::getImplementationName()
    {
        return OUString( "com.sun.star.comp.ucb.PropertySetRegistry" );
    }

    sal_Bool SAL_CALL PropertySetRegistry::supportsService( const OUString& ServiceName )
    {
        return cppu::supportsService( this, ServiceName );
    }

    css::uno::Sequence< OUString > SAL_CALL PropertySetRegistry::getSupportedServiceNames()
    {
        return { PROPSET_REG_SERVICE_NAME };
    }

    // XPropertySetRegistry methods.

    // virtual
    Reference< XPersistentPropertySet > SAL_CALL
    PropertySetRegistry::openPropertySet( const OUString& key, sal_Bool create )
    {
        if ( !key.isEmpty() )
        {
            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 instantiated.
                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(
                                                        *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 container!" );

                        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...

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

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

                                OSL_FAIL( "PropertySetRegistry::openPropertySet - "
                                            "caught IllegalArgumentException!" );
                            }
                            catch (const ElementExistException&)
                            {
                                // insertByName

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

                                OSL_FAIL( "PropertySetRegistry::openPropertySet - "
                                            "caught WrappedTargetException!" );
                            }
                            catch (const RuntimeException&)
                            {
                                OSL_FAIL( "PropertySetRegistry::openPropertySet - "
                                            "caught RuntimeException!" );
                            }
                            catch (const Exception&)
                            {
                                // createInstance

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

                SAL_WARN( "ucb", "no root access" );
            }
        }

        return Reference< XPersistentPropertySet >();
    }

    // virtual
    void SAL_CALL PropertySetRegistry::removePropertySet( const OUString& key )
    {
        if ( key.isEmpty() )
            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 );

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

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

                    OSL_FAIL( "PropertySetRegistry::removePropertySet - "
                                "caught NoSuchElementException!" );
                    return;
                }
                catch (const WrappedTargetException&)
                {
                    // commitChanges

                    OSL_FAIL( "PropertySetRegistry::removePropertySet - "
                                "caught WrappedTargetException!" );
                    return;
                }
            }

            return;
        }

        SAL_WARN( "ucb", "no root access" );
    }

    // XElementAccess methods.

    // virtual
    css::uno::Type SAL_CALL PropertySetRegistry::getElementType()
    {
        return cppu::UnoType<XPersistentPropertySet>::get();
    }

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

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

        return false;
    }

    // XNameAccess methods.

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

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

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

        return Any();
    }

    // virtual
    Sequence< OUString > SAL_CALL PropertySetRegistry::getElementNames()
    {
        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 )
    {
        osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

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

        return false;
    }

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

        if ( !key.isEmpty() )
        {
            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.isEmpty() )
        {
            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_FAIL( "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 (const IllegalArgumentException&)
                    {
                        // insertByName

                        OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
                                    "caught IllegalArgumentException!" );
                        return;
                    }
                    catch (const ElementExistException&)
                    {
                        // insertByName

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

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

                        OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
                                    "caught Exception!" );
                        return;
                    }

                    // Copy data...

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

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

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

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

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

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

                            aOldValuesKey += "/";

                            OUString const aHandleKey("/Handle");
                            OUString const aValueKey("/Value");
                            OUString const aStateKey("/State");
                            OUString const aAttrKey("/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_FAIL( "PersistentPropertySet::renamePropertySet - "
                                        "No new prop name replace!" );
                                    return;
                                }

                                // Fill new item...

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

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

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

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

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

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

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

                        OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
                                    "caught IllegalArgumentException!" );
                        return;
                    }
                    catch (const ElementExistException&)
                    {
                        // insertByName

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

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

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

                        OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
                                    "caught Exception!" );
                        return;
                    }

                    // Remove old entry...

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

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

                        OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
                                    "caught NoSuchElementException!" );
                        return;
                    }
                    catch (const WrappedTargetException&)
                    {
                        // commitChanges

                        OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
                                    "caught WrappedTargetException!" );
                        return;
                    }
                }
            }
        }

        OSL_FAIL( "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 = theDefaultProvider::get( m_xContext );
                    }
                    catch (const Exception&)
                    {
                        SAL_WARN( "ucb", "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 )
                {
                    OSL_FAIL( "PropertySetRegistry::getRootConfigReadAccess - "
                                "Unable to read any config data! -> #82494#" );
                    return Reference< XInterface >();
                }

                getConfigProvider();

                if ( m_pImpl->m_xConfigProvider.is() )
                {
                    Sequence<Any> aArguments(comphelper::InitAnyPropertySequence(
                    {
                        {CFGPROPERTY_NODEPATH,  Any(OUString( STORE_CONTENTPROPERTIES_KEY ))}
                    }));

                    m_pImpl->m_bTriedToGetRootReadAccess = true;

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

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

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

        SAL_WARN( "ucb", "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 )
                {
                    OSL_FAIL( "PropertySetRegistry::getConfigWriteAccess - "
                                "Unable to write any config data! -> #82494#" );
                    return Reference< XInterface >();
                }

                getConfigProvider();

                if ( m_pImpl->m_xConfigProvider.is() )
                {
                    Sequence<Any> aArguments(comphelper::InitAnyPropertySequence(
                    {
                        {CFGPROPERTY_NODEPATH,  Any(OUString( STORE_CONTENTPROPERTIES_KEY ))}
                    }));

                    m_pImpl->m_bTriedToGetRootWriteAccess = true;

                    m_pImpl->m_xRootWriteAccess =
                        m_pImpl->m_xConfigProvider->createInstanceWithArguments(
                            "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.isEmpty() )
                {
                    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 (const RuntimeException&)
        {
            throw;
        }
        catch (const NoSuchElementException&)
        {
            // getByHierarchicalName

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

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

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

    typedef OMultiTypeInterfaceContainerHelperVar<OUString> PropertyListeners_Impl;

    struct PersistentPropertySet_Impl
    {
        rtl::Reference<PropertySetRegistry>  m_pCreator;
        rtl::Reference<PropertySetInfo_Impl> m_pInfo;
        OUString                    m_aKey;
        OUString                    m_aFullKey;
        osl::Mutex                  m_aMutex;
        std::unique_ptr<OInterfaceContainerHelper2>  m_pDisposeEventListeners;
        std::unique_ptr<OInterfaceContainerHelper2>  m_pPropSetChangeListeners;
        std::unique_ptr<PropertyListeners_Impl>      m_pPropertyChangeListeners;

        PersistentPropertySet_Impl( PropertySetRegistry& rCreator,
                                    const OUString& rKey )
        : m_pCreator( &rCreator ), m_aKey( rKey )
        {
        }
    };

    // PersistentPropertySet Implementation.

    PersistentPropertySet::PersistentPropertySet(
                            PropertySetRegistry& rCreator,
                            const OUString& rKey )
    : 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 );
    }

    // XServiceInfo methods.

    OUString SAL_CALL PersistentPropertySet::getImplementationName()
    {
        return OUString( "com.sun.star.comp.ucb.PersistentPropertySet" );
    }

    sal_Bool SAL_CALL PersistentPropertySet::supportsService( const OUString& ServiceName )
    {
        return cppu::supportsService( this, ServiceName );
    }

    css::uno::Sequence< OUString > SAL_CALL
    PersistentPropertySet::getSupportedServiceNames()
    {
        return { PERS_PROPSET_SERVICE_NAME };
    }

    // XComponent methods.

    // virtual
    void SAL_CALL PersistentPropertySet::dispose()
    {
        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 )
    {
        if ( !m_pImpl->m_pDisposeEventListeners )
            m_pImpl->m_pDisposeEventListeners.reset(
                        new OInterfaceContainerHelper2( m_pImpl->m_aMutex ) );

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

    // virtual
    void SAL_CALL PersistentPropertySet::removeEventListener(
                                const Reference< XEventListener >& Listener )
    {
        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()
    {
        osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

        if ( !m_pImpl->m_pInfo.is() )
        {
            m_pImpl->m_pInfo = new PropertySetInfo_Impl( this );
        }
        return Reference< XPropertySetInfo >( m_pImpl->m_pInfo.get() );
    }

    // virtual
    void SAL_CALL PersistentPropertySet::setPropertyValue( const OUString& aPropertyName,
                                                           const Any& aValue )
    {
        if ( aPropertyName.isEmpty() )
            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 += "/";
            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 += "/Value";
                        Any aOldValue
                            = xRootHierNameAccess->getByHierarchicalName(
                                                                    aValueName );
                        // Check value type.
                        if ( aOldValue.getValueType() != aValue.getValueType() )
                        {
                            aCGuard.clear();
                            throw IllegalArgumentException();
                        }

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

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

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

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

                            aEvt.Source         = static_cast<OWeakObject*>(this);
                            aEvt.PropertyName   = aPropertyName;
                            aEvt.PropertyHandle = nHandle;
                            aEvt.Further        = false;
                            aEvt.OldValue       = aOldValue;
                            aEvt.NewValue       = aValue;

                            // Callback follows!
                            aCGuard.clear();

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

        throw UnknownPropertyException();
    }

    // virtual
    Any SAL_CALL PersistentPropertySet::getPropertyValue(
                                                const OUString& PropertyName )
    {
        if ( PropertyName.isEmpty() )
            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 += "/";
            aFullPropName += makeHierarchalNameSegment( PropertyName );
            aFullPropName += "/Value";
            try
            {
                return xNameAccess->getByHierarchicalName( aFullPropName );
            }
            catch (const NoSuchElementException&)
            {
                throw UnknownPropertyException();
            }
        }

        throw UnknownPropertyException();
    }

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

        if ( !m_pImpl->m_pPropertyChangeListeners )
            m_pImpl->m_pPropertyChangeListeners.reset(
                        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 )
    {
    //  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 >& )
    {
    //  load();
    //  OSL_FAIL( //                "PersistentPropertySet::addVetoableChangeListener - N.Y.I." );
    }

    // virtual
    void SAL_CALL PersistentPropertySet::removeVetoableChangeListener(
                        const OUString&,
                        const Reference< XVetoableChangeListener >& )
    {
    //  load();
    //  OSL_FAIL( //                "PersistentPropertySet::removeVetoableChangeListener - N.Y.I." );
    }

    // XPersistentPropertySet methods.

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

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

    // XNamed methods.

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

    // virtual
    void SAL_CALL PersistentPropertySet::setName( const OUString& aName )
    {
        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 )
    {
        if ( Name.isEmpty() )
            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 += "/";
            aFullPropName += makeHierarchalNameSegment( Name );

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

        // Property is always removable.
        Attributes |= PropertyAttribute::REMOVABLE;

        // 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(
                                        "Handle",
                                        makeAny( sal_Int32( -1 ) ) );

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

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

                    // Set attributes
                    xNameReplace->replaceByName(
                                        "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.is() )
                        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 (const IllegalArgumentException&)
            {
                // insertByName

                OSL_FAIL( "PersistentPropertySet::addProperty - "
                            "caught IllegalArgumentException!" );
                return;
            }
            catch (const ElementExistException&)
            {
                // insertByName

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

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

                OSL_FAIL( "PersistentPropertySet::addProperty - "
                            "caught Exception!" );
                return;
            }
        }

        OSL_FAIL( "PersistentPropertySet::addProperty - Error!" );
    }

    // virtual
    void SAL_CALL PersistentPropertySet::removeProperty( const OUString& Name )
    {
        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   += "/";
            aFullPropName   += makeHierarchalNameSegment( Name );

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

            // Property removable?
            try
            {
                OUString aFullAttrName = aFullPropName;
                aFullAttrName += "/Attributes";

                sal_Int32 nAttribs = 0;
                if ( xRootHierNameAccess->getByHierarchicalName( aFullAttrName )
                        >>= nAttribs )
                {
                    if ( !( nAttribs & PropertyAttribute::REMOVABLE ) )
                    {
                        // Not removable!
                        throw NotRemoveableException();
                    }
                }
                else
                {
                    OSL_FAIL( "PersistentPropertySet::removeProperty - "
                                "No attributes!" );
                    return;
                }
            }
            catch (const NoSuchElementException&)
            {
                // getByHierarchicalName

                OSL_FAIL( "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
                                    += "/Handle";

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

                        }
                        catch (const NoSuchElementException&)
                        {
                            // getByHierarchicalName

                            OSL_FAIL( "PersistentPropertySet::removeProperty - "
                                        "caught NoSuchElementException!" );
                            nHandle = -1;
                        }
                    }

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

                    // Property set info is invalid.
                    if ( m_pImpl->m_pInfo.is() )
                        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 (const NoSuchElementException&)
                {
                    // removeByName

                    OSL_FAIL( "PersistentPropertySet::removeProperty - "
                                "caught NoSuchElementException!" );
                    return;
                }
                catch (const WrappedTargetException&)
                {
                    // commitChanges

                    OSL_FAIL( "PersistentPropertySet::removeProperty - "
                                "caught WrappedTargetException!" );
                    return;
                }
            }
        }

        OSL_FAIL( "PersistentPropertySet::removeProperty - Error!" );
    }

    // XPropertySetInfoChangeNotifier methods.

    // virtual
    void SAL_CALL PersistentPropertySet::addPropertySetInfoChangeListener(
                    const Reference< XPropertySetInfoChangeListener >& Listener )
    {
        if ( !m_pImpl->m_pPropSetChangeListeners )
            m_pImpl->m_pPropSetChangeListeners.reset(
                        new OInterfaceContainerHelper2( m_pImpl->m_aMutex ) );

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

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

    // XPropertyAccess methods.

    // virtual
    Sequence< PropertyValue > SAL_CALL PersistentPropertySet::getPropertyValues()
    {
        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("/Handle");
                            const OUString aValueName("/Value");
                            const OUString aStateName("/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_FAIL( "PersistentPropertySet::getPropertyValues - "
                                          "Error getting property handle!" );
                                }
                                catch (const NoSuchElementException&)
                                {
                                    // getByHierarchicalName

                                    OSL_FAIL( "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 (const NoSuchElementException&)
                                {
                                    // getByHierarchicalName

                                    OSL_FAIL( "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_FAIL( "PersistentPropertySet::getPropertyValues - "
                                          "Error getting property state!" );
                                    else
                                        rValue.State = PropertyState( nState );
                                }
                                catch (const NoSuchElementException&)
                                {
                                    // getByHierarchicalName

                                    OSL_FAIL( "PersistentPropertySet::getPropertyValues - "
                                      "NoSuchElementException!" );
                                }
                            }

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

        return Sequence< PropertyValue >( 0 );
    }

    // virtual
    void SAL_CALL PersistentPropertySet::setPropertyValues(
                                     const Sequence< PropertyValue >& aProps )
    {
        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();

            std::vector< PropertyChangeEvent > aEvents;

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

            // 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(
                                        "Handle",
                                        makeAny( rNewValue.Handle ) );

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

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

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

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

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

            // Callback follows!
            aCGuard.clear();

            if ( m_pImpl->m_pPropertyChangeListeners )
            {
                // Notify property changes.
                for (auto const& event : aEvents)
                {
                    notifyPropertyChangeEvent( event );
                }
            }

            return;
        }

        OSL_FAIL( "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.
        OInterfaceIteratorHelper2 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.isEmpty() )
        {
            osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
            if ( m_pImpl->m_aFullKey.isEmpty() )
            {
                m_pImpl->m_aFullKey
                    = makeHierarchalNameSegment( m_pImpl->m_aKey );
                m_pImpl->m_aFullKey
                    += "/Values";
            }
        }

        return m_pImpl->m_aFullKey;
    }

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

    // PropertySetInfo_Impl Implementation.

    PropertySetInfo_Impl::PropertySetInfo_Impl(
                            PersistentPropertySet* pOwner )
    : m_pOwner( pOwner )
    {
    }

    // XPropertySetInfo methods.

    // virtual
    Sequence< Property > SAL_CALL PropertySetInfo_Impl::getProperties()
    {
        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("/Handle");
                                const OUString aValueName("/Value");
                                const OUString aAttrName("/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
                                        OUString aHierName = aXMLName;
                                        aHierName += aHandleName;
                                        Any aKeyValue
                                            = xHierNameAccess->getByHierarchicalName(
                                                aHierName );

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

                                        OSL_FAIL( "PropertySetInfo_Impl::getProperties - "
                                          "NoSuchElementException!" );
                                    }

                                    try
                                    {
                                        // Obtain and set property type
                                        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 (const NoSuchElementException&)
                                    {
                                        // getByHierarchicalName

                                        OSL_FAIL( "PropertySetInfo_Impl::getProperties - "
                                          "NoSuchElementException!" );
                                    }

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

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

                                        OSL_FAIL( "PropertySetInfo_Impl::getProperties - "
                                          "NoSuchElementException!" );
                                    }
                                }
                            }
                        }

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

            OSL_FAIL( "PropertySetInfo_Impl::getProperties - Error!" );
            m_pProps.reset( new Sequence< Property >( 0 ) );
        }

        return *m_pProps;
    }

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

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

            try
            {
                Property aProp;

                // Obtain handle.
                OUString aKey = aFullPropName;
                aKey += "/Handle";

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

                // Obtain Value and extract type.
                aKey = aFullPropName;
                aKey += "/Value";

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

                aProp.Type = aValue.getValueType();

                // Obtain Attributes.
                aKey = aFullPropName;
                aKey += "/Attributes";

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

                // set name.
                aProp.Name = aName;

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

                OSL_FAIL( "PropertySetInfo_Impl::getPropertyByName - "
                            "caught NoSuchElementException!" );
            }

        }

        OSL_FAIL( "PropertySetInfo_Impl::getPropertyByName - Error!" );
        return Property();
    }

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

            return xRootHierNameAccess->hasByHierarchicalName( aFullPropName );
        }

        return false;
    }

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V572 It is odd that the object which was created using 'new' operator is immediately cast to another type.