Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  introspection.cxx   Sprache: C

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


#include <sal/config.h>

#include <cassert>
#include <cstddef>
#include <limits>
#include <map>
#include <memory>
#include <mutex>
#include <set>

#include <o3tl/any.hxx>
#include <o3tl/string_view.hxx>
#include <osl/diagnose.h>
#include <sal/log.hxx>
#include <cppuhelper/basemutex.hxx>
#include <cppuhelper/compbase.hxx>
#include <cppuhelper/queryinterface.hxx>
#include <cppuhelper/weak.hxx>
#include <cppuhelper/implbase.hxx>
#include <cppuhelper/supportsservice.hxx>
#include <comphelper/sequence.hxx>
#include <salhelper/simplereferenceobject.hxx>

#include <com/sun/star/lang/NoSuchMethodException.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XUnoTunnel.hpp>
#include <com/sun/star/reflection/XIdlReflection.hpp>
#include <com/sun/star/reflection/XIdlClass.hpp>
#include <com/sun/star/reflection/XIdlField2.hpp>
#include <com/sun/star/reflection/theCoreReflection.hpp>
#include <com/sun/star/beans/UnknownPropertyException.hpp>
#include <com/sun/star/beans/Property.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/XFastPropertySet.hpp>
#include <com/sun/star/beans/XIntrospection.hpp>
#include <com/sun/star/beans/XIntrospectionAccess.hpp>
#include <com/sun/star/beans/XMaterialHolder.hpp>
#include <com/sun/star/beans/XExactName.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/beans/PropertyConcept.hpp>
#include <com/sun/star/beans/MethodConcept.hpp>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/container/XIndexContainer.hpp>
#include <com/sun/star/container/XEnumerationAccess.hpp>

#include <rtl/ref.hxx>
#include <rtl/ustrbuf.hxx>
#include <unordered_map>
#include <utility>

using namespace css::uno;
using namespace css::lang;
using namespace css::reflection;
using namespace css::container;
using namespace css::beans;
using namespace css::beans::PropertyAttribute;
using namespace css::beans::PropertyConcept;
using namespace css::beans::MethodConcept;
using namespace cppu;
using namespace osl;

namespace
{

typedef WeakImplHelper< XIntrospectionAccess, XMaterialHolder, XExactName,
                        XPropertySet, XFastPropertySet, XPropertySetInfo,
                        XNameContainer, XIndexContainer, XEnumerationAccess,
                        XIdlArray, XUnoTunnel > IntrospectionAccessHelper;


// Special value for Method-Concept, to be able to mark "normal" functions
#define  MethodConcept_NORMAL_IMPL        0x80000000


// Method to assert, if a class is derived from another class
bool isDerivedFrom( const Reference<XIdlClass>& xToTestClass, const Reference<XIdlClass>& xDerivedFromClass )
{
    const Sequence< Reference<XIdlClass> > aClassesSeq = xToTestClass->getSuperclasses();

    return std::any_of(aClassesSeq.begin(), aClassesSeq.end(),
        [&xDerivedFromClass](const Reference<XIdlClass>& rxClass) {
            return xDerivedFromClass->equals( rxClass )
                || isDerivedFrom( rxClass, xDerivedFromClass );
        });
}


// *** Classification of Properties (no enum, to be able to use Sequence) ***
// Properties from a PropertySet-Interface
#define MAP_PROPERTY_SET    0
// Properties from Fields
#define MAP_FIELD            1
// Properties that get described with get/set methods
#define MAP_GETSET            2
// Properties with only a set method
#define MAP_SETONLY            3


// Increments by which the size of sequences get adjusted
#define ARRAY_SIZE_STEP        20


//*** IntrospectionAccessStatic_Impl ***

// Equals to the old IntrospectionAccessImpl, forms now a static
// part of the new Instance-related ImplIntrospectionAccess

// Hashtable for the search of names
typedef std::unordered_map
<
    OUString,
    sal_Int32
>
IntrospectionNameMap;


// Hashtable to assign exact names to the Lower-Case
// converted names, for the support of XExactName
typedef std::unordered_map
<
    OUString,
    OUString
>
LowerToExactNameMap;


class IntrospectionAccessStatic_Impl: public salhelper::SimpleReferenceObject
{
    friend class Implementation;
    friend class ImplIntrospectionAccess;

    // Holding CoreReflection
    Reference< XIdlReflection > mxCoreReflection;

    // InterfaceSequences, to save additional information in a property
    // for example the Field at MAP_FIELD, the get/set-Methods at MAP_GETSET, et cetera
    std::vector< Reference<XInterface> > aInterfaceSeq1;
    std::vector< Reference<XInterface> > aInterfaceSeq2;

    // Hashtables for names
    IntrospectionNameMap maPropertyNameMap;
    IntrospectionNameMap maMethodNameMap;
    LowerToExactNameMap  maLowerToExactNameMap;

    // Vector of all Properties, also for delivering from getProperties()
    std::vector<Property> maAllPropertySeq;

    // Mapping of properties to Access-Types
    std::vector<sal_Int16> maMapTypeSeq;

    // Classification of found methods
    std::vector<sal_Int32> maPropertyConceptSeq;

    // Number of Properties
    sal_Int32 mnPropCount;

    // Number of Properties, which are assigned to particular concepts
    //sal_Int32 mnDangerousPropCount;
    sal_Int32 mnPropertySetPropCount;
    sal_Int32 mnAttributePropCount;
    sal_Int32 mnMethodPropCount;

    // Flags which indicate if various interfaces are present
    bool mbFastPropSet;
    bool mbElementAccess;
    bool mbNameAccess;
    bool mbNameReplace;
    bool mbNameContainer;
    bool mbIndexAccess;
    bool mbIndexReplace;
    bool mbIndexContainer;
    bool mbEnumerationAccess;
    bool mbIdlArray;
    bool mbUnoTunnel;

    // Original handles of FastPropertySets
    std::unique_ptr<sal_Int32[]> mpOrgPropertyHandleArray;

    // MethodSequence, that accepts all methods
    std::vector< Reference<XIdlMethod> > maAllMethodSeq;

    // Classification of found methods
    std::vector<sal_Int32> maMethodConceptSeq;

    // Number of methods
    sal_Int32 mnMethCount;

    // Sequence of Listener, that can be registered
    std::vector< Type > maSupportedListenerSeq;

    // Helper-methods for adjusting sizes of Sequences
    void checkPropertyArraysSize( sal_Int32 iNextIndex );
    static void checkInterfaceArraySize( std::vector< Reference<XInterface> >& rSeq, std::vector<Reference<XInterface>>& rInterfaceVec,
        sal_Int32 iNextIndex );

public:
    explicit IntrospectionAccessStatic_Impl( Reference< XIdlReflection > const & xCoreReflection_ );
    sal_Int32 getPropertyIndex( const OUString& aPropertyName ) const;
    sal_Int32 getMethodIndex( const OUString& aMethodName ) const;

    // Methods of XIntrospectionAccess (OLD, now only Impl)
    void setPropertyValue(const Any& obj, const OUString& aPropertyName, const Any&&nbsp;aValue) const;
//    void setPropertyValue(Any& obj, const OUString& aPropertyName, const Any& aValue) const;
    Any getPropertyValue(const Any& obj, const OUString& aPropertyName) const;
    void setPropertyValueByIndex(const Any& obj, sal_Int32 nIndex, const Any& aValueconst;
//    void setPropertyValueByIndex(Any& obj, sal_Int32 nIndex, const Any& aValue) const;
    Any getPropertyValueByIndex(const Any& obj, sal_Int32 nIndex) const;

    const std::vector<Property>& getProperties() const              { return maAllPropertySeq; }
    const std::vector< Reference<XIdlMethod> >& getMethods() const  { return maAllMethodSeq; }
    const std::vector< Type >& getSupportedListeners() const        { return maSupportedListenerSeq; }
    const std::vector<sal_Int32>& getPropertyConcepts() const       { return maPropertyConceptSeq; }
    const std::vector<sal_Int32>& getMethodConcepts() const         { return maMethodConceptSeq; }
};


// Ctor
IntrospectionAccessStatic_Impl::IntrospectionAccessStatic_Impl( Reference< XIdlReflection > const & xCoreReflection_ )
    : mxCoreReflection( xCoreReflection_ )
{
    aInterfaceSeq1.resize( ARRAY_SIZE_STEP );
    aInterfaceSeq2.resize( ARRAY_SIZE_STEP );

    // Property-Data
    maAllPropertySeq.resize( ARRAY_SIZE_STEP );
    maMapTypeSeq.resize( ARRAY_SIZE_STEP );
    maPropertyConceptSeq.resize( ARRAY_SIZE_STEP );

    mbFastPropSet = false;
    mbElementAccess = false;
    mbNameAccess = false;
    mbNameReplace = false;
    mbNameContainer = false;
    mbIndexAccess = false;
    mbIndexReplace = false;
    mbIndexContainer = false;
    mbEnumerationAccess = false;
    mbIdlArray = false;
    mbUnoTunnel = false;

    mpOrgPropertyHandleArray = nullptr;

    mnPropCount = 0;
    //mnDangerousPropCount = 0;
    mnPropertySetPropCount = 0;
    mnAttributePropCount = 0;
    mnMethodPropCount = 0;

    // Method-Data
    mnMethCount = 0;
}

sal_Int32 IntrospectionAccessStatic_Impl::getPropertyIndex( const OUString& aPropertyName ) const
{
    auto aIt = maPropertyNameMap.find(aPropertyName);
    if (aIt != maPropertyNameMap.end())
        return aIt->second;

    return -1;
}

sal_Int32 IntrospectionAccessStatic_Impl::getMethodIndex( const OUString& aMethodName ) const
{
    auto aIt = maMethodNameMap.find(aMethodName);
    if (aIt != maMethodNameMap.end())
    {
        return aIt->second;
    }

    // #95159 Check if full qualified name matches
    sal_Int32 nSearchFrom = aMethodName.getLength();
    whiletrue )
    {
        // Strategy: Search back until the first '_' is found
        sal_Int32 nFound = aMethodName.lastIndexOf( '_', nSearchFrom );
        if( nFound == -1 )
            break;

        OUString aPureMethodName = aMethodName.copy( nFound + 1 );

        aIt = maMethodNameMap.find( aPureMethodName );
        if (aIt != maMethodNameMap.end())
        {
            // Check if it can be a type?
            // Problem: Does not work if package names contain _ ?!
            OUString aStr = aMethodName.copy( 0, nFound );
            OUString aTypeName = aStr.replace( '_''.' );
            Reference< XIdlClass > xClass = mxCoreReflection->forName( aTypeName );
            if( xClass.is() )
            {
                // If this is a valid class it could be the right method

                // Could be the right method, type has to be checked
                const sal_Int32 iHashResult = aIt->second;

                const Reference<XIdlMethod> xMethod = maAllMethodSeq[iHashResult];

                Reference< XIdlClass > xMethClass = xMethod->getDeclaringClass();
                if( xClass->equals( xMethClass ) )
                {
                    return iHashResult;
                }
                else
                {
                    // Could also be another method with the same name
                    // Iterate over all methods
                    size_t nLen = maAllMethodSeq.size();
                    for (size_t i = 0; i < nLen; ++i)
                    {
                        const Reference<XIdlMethod> xMethod2 = maAllMethodSeq[ i ];
                        if( xMethod2->getName() == aPureMethodName )
                        {
                            Reference< XIdlClass > xMethClass2 = xMethod2->getDeclaringClass();

                            if( xClass->equals( xMethClass2 ) )
                            {
                                return i;
                            }
                        }
                    }
                }
            }
        }

        nSearchFrom = nFound - 1;
        if( nSearchFrom < 0 )
            break;
    }
    return -1;
}

void IntrospectionAccessStatic_Impl::setPropertyValue( const Any& obj, const OUString& aPropertyName, const Any& aValue ) const
//void IntrospectionAccessStatic_Impl::setPropertyValue( Any& obj, const OUString&&nbsp;aPropertyName, const Any& aValue ) const
{
    sal_Int32 i = getPropertyIndex( aPropertyName );
    if( i == -1 )
        throw UnknownPropertyException(aPropertyName);
    setPropertyValueByIndex( obj, i, aValue );
}

void IntrospectionAccessStatic_Impl::setPropertyValueByIndex(const Any& obj, sal_Int32 nSequenceIndex, const Any& aValue) const
//void IntrospectionAccessStatic_Impl::setPropertyValueByIndex( Any& obj, sal_Int32 nSequenceIndex, const Any& aValue) const
{
    // Is the passed object something that fits?
    Reference<XInterface> xInterface;
    if( !(obj >>= xInterface) )
    {
        TypeClass eObjType = obj.getValueTypeClass();
        if( nSequenceIndex >= mnPropCount)
            throw IllegalArgumentException(
                "IntrospectionAccessStatic_Impl::setPropertyValueByIndex(), index > propertyCount, " +
                OUString::number(nSequenceIndex) + " > " + OUString::number(mnPropCount),
                Reference<XInterface>(), 0);
        if( eObjType != TypeClass_STRUCT && eObjType != TypeClass_EXCEPTION )
            throw IllegalArgumentException(
                "IntrospectionAccessStatic_Impl::setPropertyValueByIndex(), expected struct or exception, got" +
                obj.getValueTypeName(), Reference<XInterface>(), 0);
    }

    // Test flags
    if( (maAllPropertySeq[ nSequenceIndex ].Attributes & READONLY) != 0 )
    {
        throw UnknownPropertyException(
            "IntrospectionAccessStatic_Impl::setPropertyValueByIndex(), property at index " + OUString::number(nSequenceIndex) + " is readonly");
    }

    switch( maMapTypeSeq[ nSequenceIndex ] )
    {
        case MAP_PROPERTY_SET:
        {
            // Get Property
            const Property& rProp = maAllPropertySeq[ nSequenceIndex ];

            // Convert Interface-Parameter to the correct type
            bool bUseCopy = false;
            Any aRealValue;

            ifauto valInterface = o3tl::tryAccess<
                    css::uno::Reference<css::uno::XInterface>>(aValue) )
            {
                Type aPropType = rProp.Type;
                OUString aTypeName( aPropType.getTypeName() );
                Reference< XIdlClass > xPropClass = mxCoreReflection->forName( aTypeName );
                //Reference<XIdlClass> xPropClass = rProp.Type;
                if( xPropClass.is() && xPropClass->getTypeClass() == TypeClass_INTERFACE )
                {
                    if( valInterface->is() )
                    {
                        //Any queryInterface( const Type& rType );
                        aRealValue = (*valInterface)->queryInterface( aPropType );
                        if( aRealValue.hasValue() )
                            bUseCopy = true;
                    }
                }
            }

            // Do we have a FastPropertySet and a valid Handle?
            // CAUTION: At this point we exploit that the PropertySet
            // gets queried at the beginning of the Introspection-Process.
            sal_Int32 nOrgHandle;
            if( mbFastPropSet && ( nOrgHandle = mpOrgPropertyHandleArray[ nSequenceIndex ] ) != -1 )
            {
                // Retrieve PropertySet-Interface
                Reference<XFastPropertySet> xFastPropSet =
                    Reference<XFastPropertySet>::query( xInterface );
                if( xFastPropSet.is() )
                {
                    xFastPropSet->setFastPropertyValue( nOrgHandle, bUseCopy ? aRealValue : aValue );
                }
                else
                {
                    // throw UnknownPropertyException
                }
            }
            // else take the normal one
            else
            {
                // Retrieve PropertySet-Interface
                Reference<XPropertySet> xPropSet =
                    Reference<XPropertySet>::query( xInterface );
                if( xPropSet.is() )
                {
                    xPropSet->setPropertyValue( rProp.Name, bUseCopy ? aRealValue : aValue );
                }
                else
                {
                    // throw UnknownPropertyException
                }
            }
        }
        break;

        case MAP_FIELD:
        {
            Reference<XIdlField> xField = static_cast<XIdlField*>(aInterfaceSeq1[ nSequenceIndex ].get());
            Reference<XIdlField2> xField2(xField, UNO_QUERY);
            if( xField2.is() )
            {
                xField2->set( const_cast<Any&>(obj), aValue );
                // IllegalArgumentException
                // NullPointerException
            } else
            if( xField.is() )
            {
                xField->set( obj, aValue );
                // IllegalArgumentException
                // NullPointerException
            }
            else
            {
                // throw IllegalArgumentException();
            }
        }
        break;

        case MAP_GETSET:
        case MAP_SETONLY:
        {
            // Fetch set method
            Reference<XIdlMethod> xMethod = static_cast<XIdlMethod*>(aInterfaceSeq2[ nSequenceIndex ].get());
            if( xMethod.is() )
            {
                Sequence<Any> args( 1 );
                args.getArray()[0] = aValue;
                xMethod->invoke( obj, args );
            }
            else
            {
                // throw IllegalArgumentException();
            }
        }
        break;
    }
}

Any IntrospectionAccessStatic_Impl::getPropertyValue( const Any& obj, const OUString& aPropertyName ) const
{
    sal_Int32 i = getPropertyIndex( aPropertyName );
    if( i != -1 )
        return getPropertyValueByIndex( obj, i );

    throw UnknownPropertyException(aPropertyName);
}

Any IntrospectionAccessStatic_Impl::getPropertyValueByIndex(const Any& obj, sal_Int32 nSequenceIndex) const
{
    Any aRet;

    // Is there anything suitable in the passed object?
    Reference<XInterface> xInterface;
    if( !(obj >>= xInterface) )
    {
        TypeClass eObjType = obj.getValueTypeClass();
        if( nSequenceIndex >= mnPropCount || ( eObjType != TypeClass_STRUCT && eObjType != TypeClass_EXCEPTION ) )
        {
            // throw IllegalArgumentException();
            return aRet;
        }
    }

    switch( maMapTypeSeq[ nSequenceIndex ] )
    {
        case MAP_PROPERTY_SET:
        {
            // Acquire property
            const Property& rProp = maAllPropertySeq[ nSequenceIndex ];

            // Do we have a FastPropertySet and a valid handle?
            // NOTE: At this point is exploited that the PropertySet
            // is queried at the beginning of introspection process.
            sal_Int32 nOrgHandle;
            if( mbFastPropSet && ( nOrgHandle = mpOrgPropertyHandleArray[ nSequenceIndex ] ) != -1 )
            {
                // Fetch the PropertySet interface
                Reference<XFastPropertySet> xFastPropSet =
                    Reference<XFastPropertySet>::query( xInterface );
                if( xFastPropSet.is() )
                {
                    aRet = xFastPropSet->getFastPropertyValue( nOrgHandle);
                }
                else
                {
                    // throw UnknownPropertyException
                    return aRet;
                }
            }
            // Otherwise use the normal one
            else
            {
                // Fetch the PropertySet interface
                Reference<XPropertySet> xPropSet =
                    Reference<XPropertySet>::query( xInterface );
                if( xPropSet.is() )
                {
                    aRet = xPropSet->getPropertyValue( rProp.Name );
                }
                else
                {
                    // throw UnknownPropertyException
                    return aRet;
                }
            }
        }
        break;

        case MAP_FIELD:
        {
            Reference<XIdlField> xField = static_cast<XIdlField*>(aInterfaceSeq1[ nSequenceIndex ].get());
            if( xField.is() )
            {
                aRet = xField->get( obj );
                // IllegalArgumentException
                // NullPointerException
            }
            else
            {
                // throw IllegalArgumentException();
                return aRet;
            }
        }
        break;

        case MAP_GETSET:
        {
            // Fetch get method
            Reference<XIdlMethod> xMethod = static_cast<XIdlMethod*>(aInterfaceSeq1[ nSequenceIndex ].get());
            if( xMethod.is() )
            {
                Sequence<Any> args;
                aRet = xMethod->invoke( obj, args );
            }
            else
            {
                // throw IllegalArgumentException();
                return aRet;
            }
        }
        break;

        case MAP_SETONLY:
            // Get method does not exist
            // throw WriteOnlyPropertyException();
            return aRet;
    }
    return aRet;
}


// Helper method to adjust the size of the vectors
void IntrospectionAccessStatic_Impl::checkPropertyArraysSize( sal_Int32 iNextIndex )
{
    sal_Int32 nLen = static_cast<sal_Int32>(maAllPropertySeq.size());
    if( iNextIndex >= nLen )
    {
        maAllPropertySeq.resize( nLen + ARRAY_SIZE_STEP );
        maMapTypeSeq.resize( nLen + ARRAY_SIZE_STEP );
        maPropertyConceptSeq.resize( nLen + ARRAY_SIZE_STEP );
    }
}

void IntrospectionAccessStatic_Impl::checkInterfaceArraySize( std::vector< Reference<XInterface> >& rSeq,
    std::vector<Reference<XInterface>>& rInterfaceVec, sal_Int32 iNextIndex )
{
    sal_Int32 nLen = rSeq.size();
    if( iNextIndex >= nLen )
    {
        // Synchronize new size with ARRAY_SIZE_STEP
        sal_Int32 nMissingSize = iNextIndex - nLen + 1;
        sal_Int32 nSteps = nMissingSize / ARRAY_SIZE_STEP + 1;
        sal_Int32 nNewSize = nLen + nSteps * ARRAY_SIZE_STEP;

        rSeq.resize( nNewSize );
        rInterfaceVec = rSeq;
    }
}


//*** ImplIntrospectionAccess ***


// New Impl class as part of the introspection conversion to instance-bound
// Introspection with property access via XPropertySet. The old class
// ImplIntrospectionAccess lives on as IntrospectionAccessStatic_Impl
class ImplIntrospectionAccess : public IntrospectionAccessHelper
{
    friend class Implementation;

    // Object under examination
    Any maInspectedObject;

    // As interface
    Reference<XInterface> mxIface;

    // Static introspection data
    rtl::Reference< IntrospectionAccessStatic_Impl > mpStaticImpl;

    // Last Sequence that came with getProperties (optimization)
    Sequence<Property> maLastPropertySeq;
    sal_Int32 mnLastPropertyConcept;

    // Last Sequence that came with getMethods (optimization)
    Sequence<Reference<XIdlMethod> > maLastMethodSeq;
    sal_Int32 mnLastMethodConcept;

    // Guards the caching of queried interfaces
    std::mutex m_aMutex;

    // Original interfaces of the objects
    Reference<XElementAccess>       mxObjElementAccess;
    Reference<XNameContainer>       mxObjNameContainer;
    Reference<XNameReplace>         mxObjNameReplace;
    Reference<XNameAccess>          mxObjNameAccess;
    Reference<XIndexContainer>      mxObjIndexContainer;
    Reference<XIndexReplace>        mxObjIndexReplace;
    Reference<XIndexAccess>         mxObjIndexAccess;
    Reference<XEnumerationAccess>   mxObjEnumerationAccess;
    Reference<XIdlArray>            mxObjIdlArray;

    Reference<XElementAccess>       getXElementAccess();
    Reference<XNameContainer>       getXNameContainer();
    Reference<XNameReplace>         getXNameReplace();
    Reference<XNameAccess>          getXNameAccess();
    Reference<XIndexContainer>      getXIndexContainer();
    Reference<XIndexReplace>        getXIndexReplace();
    Reference<XIndexAccess>         getXIndexAccess();
    Reference<XEnumerationAccess>   getXEnumerationAccess();
    Reference<XIdlArray>            getXIdlArray();

    void cacheXNameContainer(const std::unique_lock<std::mutex>& rGuard);
    void cacheXIndexContainer(const std::unique_lock<std::mutex>& rGuard);

public:
    ImplIntrospectionAccess( Any obj, rtl::Reference< IntrospectionAccessStatic_Impl >  pStaticImpl_ );

    // Methods from XIntrospectionAccess
    virtual sal_Int32 SAL_CALL getSuppliedMethodConcepts() override;
    virtual sal_Int32 SAL_CALL getSuppliedPropertyConcepts() override;
    virtual Property SAL_CALL getProperty(const OUString& Name, sal_Int32 PropertyConcepts) override;
    virtual sal_Bool SAL_CALL hasProperty(const OUString& Name, sal_Int32 PropertyConcepts) override;
    virtual Sequence< Property > SAL_CALL getProperties(sal_Int32 PropertyConcepts) override;
    virtual Reference<XIdlMethod> SAL_CALL getMethod(const OUString& Name, sal_Int32 MethodConcepts) override;
    virtual sal_Bool SAL_CALL hasMethod(const OUString& Name, sal_Int32 MethodConcepts) override;
    virtual Sequence< Reference<XIdlMethod> > SAL_CALL getMethods(sal_Int32 MethodConcepts) override;
    virtual Sequence< Type > SAL_CALL getSupportedListeners() override;
    using OWeakObject::queryAdapter;
    virtual Reference<XInterface> SAL_CALL queryAdapter( const Type& rType ) override;

    // Methods from XMaterialHolder
    virtual Any SAL_CALL getMaterial() override;

    // Methods from XExactName
    virtual OUString SAL_CALL getExactName( const OUString& rApproximateName ) override;

    // Methods from XInterface
    virtual Any SAL_CALL queryInterface( const Type& rType ) override;
    virtual void        SAL_CALL acquire() noexcept override { OWeakObject::acquire(); }
    virtual void        SAL_CALL release() noexcept override { OWeakObject::release(); }

    // Methods from XPropertySet
    virtual Reference<XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
    virtual void SAL_CALL setPropertyValue(const OUString& aPropertyName, const Any& ;aValue) override;
    virtual Any SAL_CALL getPropertyValue(const OUString& aPropertyName) override;
    virtual void SAL_CALL addPropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener) override;
    virtual void SAL_CALL removePropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener) override;
    virtual void SAL_CALL addVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener) override;
    virtual void SAL_CALL removeVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener) override;

    // Methods from XFastPropertySet
    virtual void SAL_CALL setFastPropertyValue(sal_Int32 nHandle, const Any& aValue) override;
    virtual Any SAL_CALL getFastPropertyValue(sal_Int32 nHandle) override;

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

    // Methods from XElementAccess
    virtual Type SAL_CALL getElementType() override;
    virtual sal_Bool SAL_CALL hasElements() override;

    // Methods from XNameAccess
    virtual Any SAL_CALL getByName(const OUString& Name) override;
    virtual Sequence< OUString > SAL_CALL getElementNames() override;
    virtual sal_Bool SAL_CALL hasByName(const OUString& Name) override;

    // Methods from XNameReplace
    virtual void SAL_CALL replaceByName(const OUString& Name, const Any& Element) override;

    // Methods from XNameContainer
    virtual void SAL_CALL insertByName(const OUString& Name, const Any& Element) override;
    virtual void SAL_CALL removeByName(const OUString& Name) override;

    // Methods from XIndexAccess
    virtual sal_Int32 SAL_CALL getCount() override;
    virtual Any SAL_CALL getByIndex(sal_Int32 Index) override;

    // Methods from XIndexReplace
    virtual void SAL_CALL replaceByIndex(sal_Int32 Index, const Any& Element) override;

    // Methods from XIndexContainer
    virtual void SAL_CALL insertByIndex(sal_Int32 Index, const Any& Element) override;
    virtual void SAL_CALL removeByIndex(sal_Int32 Index) override;

    // Methods from XEnumerationAccess
    virtual Reference<XEnumeration> SAL_CALL createEnumeration() override;

    // Methods from XIdlArray
    virtual void SAL_CALL realloc(Any& array, sal_Int32 length) override;
    virtual sal_Int32 SAL_CALL getLen(const Any& array) override;
    virtual Any SAL_CALL get(const Any& array, sal_Int32 index) override;
    virtual void SAL_CALL set(Any& array, sal_Int32 index, const Any& value) override;

    // Methods from XUnoTunnel
    virtual sal_Int64 SAL_CALL getSomething( const Sequence< sal_Int8 >& aIdentifier ) override;
};

ImplIntrospectionAccess::ImplIntrospectionAccess
    ( Any obj, rtl::Reference< IntrospectionAccessStatic_Impl >  pStaticImpl_ )
        : maInspectedObject(std::move( obj )), mpStaticImpl(std::move( pStaticImpl_ )) ,
          mnLastPropertyConcept(-1), mnLastMethodConcept(-1) //, maAdapter()
{
    // Save object as an interface if possible
    maInspectedObject >>= mxIface;
}

Reference<XElementAccess> ImplIntrospectionAccess::getXElementAccess()
{
    std::unique_lock aGuard( m_aMutex );
    if( !mxObjElementAccess.is() )
        mxObjElementAccess.set( mxIface, UNO_QUERY );
    return mxObjElementAccess;
}

void ImplIntrospectionAccess::cacheXNameContainer(const std::unique_lock<std::mutex>&&nbsp;/*rGuard*/)
{
    Reference<XNameContainer> xNameContainer;
    Reference<XNameReplace> xNameReplace;
    Reference<XNameAccess> xNameAccess;
    if (mpStaticImpl->mbNameContainer)
    {
        xNameContainer.set( mxIface, UNO_QUERY );
        xNameReplace = xNameContainer;
        xNameAccess = xNameContainer;
    }
    else if (mpStaticImpl->mbNameReplace)
    {
        xNameReplace.set( mxIface, UNO_QUERY );
        xNameAccess = xNameReplace;
    }
    else if (mpStaticImpl->mbNameAccess)
    {
        xNameAccess.set( mxIface, UNO_QUERY );
    }

    {
        if( !mxObjNameContainer.is() )
            mxObjNameContainer = std::move(xNameContainer);
        if( !mxObjNameReplace.is() )
            mxObjNameReplace = std::move(xNameReplace);
        if( !mxObjNameAccess.is() )
            mxObjNameAccess = std::move(xNameAccess);
    }
}

Reference<XNameContainer> ImplIntrospectionAccess::getXNameContainer()
{
    std::unique_lock aGuard( m_aMutex );

    if( !mxObjNameContainer.is() )
        cacheXNameContainer(aGuard);

    return mxObjNameContainer;
}

Reference<XNameReplace> ImplIntrospectionAccess::getXNameReplace()
{
    std::unique_lock aGuard( m_aMutex );

    if( !mxObjNameReplace.is() )
        cacheXNameContainer(aGuard);

    return mxObjNameReplace;
}

Reference<XNameAccess> ImplIntrospectionAccess::getXNameAccess()
{
    std::unique_lock aGuard( m_aMutex );

    if( !mxObjNameAccess.is() )
        cacheXNameContainer(aGuard);

    return mxObjNameAccess;
}

void ImplIntrospectionAccess::cacheXIndexContainer(const std::unique_lock<std::mutex>& /*rGuard*/)
{
    Reference<XIndexContainer> xIndexContainer;
    Reference<XIndexReplace> xIndexReplace;
    Reference<XIndexAccess> xIndexAccess;
    if (mpStaticImpl->mbIndexContainer)
    {
        xIndexContainer.set( mxIface, UNO_QUERY );
        xIndexReplace = xIndexContainer;
        xIndexAccess = xIndexContainer;
    }
    else if (mpStaticImpl->mbIndexReplace)
    {
        xIndexReplace.set( mxIface, UNO_QUERY );
        xIndexAccess = xIndexReplace;
    }
    else if (mpStaticImpl->mbIndexAccess)
    {
        xIndexAccess.set( mxIface, UNO_QUERY );
    }

    {
        if( !mxObjIndexContainer.is() )
            mxObjIndexContainer = std::move(xIndexContainer);
        if( !mxObjIndexReplace.is() )
            mxObjIndexReplace = std::move(xIndexReplace);
        if( !mxObjIndexAccess.is() )
            mxObjIndexAccess = std::move(xIndexAccess);
    }
}

Reference<XIndexContainer> ImplIntrospectionAccess::getXIndexContainer()
{
    std::unique_lock aGuard( m_aMutex );

    if( !mxObjIndexContainer.is() )
        cacheXIndexContainer(aGuard);

    return mxObjIndexContainer;
}

Reference<XIndexReplace> ImplIntrospectionAccess::getXIndexReplace()
{
    std::unique_lock aGuard( m_aMutex );

    if( !mxObjIndexReplace.is() )
        cacheXIndexContainer(aGuard);

    return mxObjIndexReplace;
}

Reference<XIndexAccess> ImplIntrospectionAccess::getXIndexAccess()
{
    std::unique_lock aGuard( m_aMutex );

    if( !mxObjIndexAccess.is() )
        cacheXIndexContainer(aGuard);

    return mxObjIndexAccess;
}

Reference<XEnumerationAccess> ImplIntrospectionAccess::getXEnumerationAccess()
{
    std::unique_lock aGuard( m_aMutex );
    if( !mxObjEnumerationAccess.is() )
        mxObjEnumerationAccess.set( mxIface, UNO_QUERY );
    return mxObjEnumerationAccess;
}

Reference<XIdlArray> ImplIntrospectionAccess::getXIdlArray()
{
    std::unique_lock aGuard( m_aMutex );
    if( !mxObjIdlArray.is() )
        mxObjIdlArray.set( mxIface, UNO_QUERY );
    return mxObjIdlArray;
}

// Methods from XInterface
Any SAL_CALL ImplIntrospectionAccess::queryInterface( const Type& rType )
{
    Any aRet( ::cppu::queryInterface(
        rType,
        static_cast< XIntrospectionAccess * >( this ),
        static_cast< XMaterialHolder * >( this ),
        static_cast< XExactName * >( this ),
        static_cast< XPropertySet * >( this ),
        static_cast< XFastPropertySet * >( this ),
        static_cast< XPropertySetInfo * >( this ) ) );
    if( !aRet.hasValue() )
        aRet = OWeakObject::queryInterface( rType );

    if( !aRet.hasValue() )
    {
        // Wrapper for the object interfaces
        ( mpStaticImpl->mbElementAccess && (aRet = ::cppu::queryInterface
                    ( rType, static_cast< XElementAccess* >( static_cast< XNameAccess* >( this ) ) ) ).hasValue() )
        || ( mpStaticImpl->mbNameAccess && (aRet = ::cppu::queryInterface( rType, static_cast< XNameAccess* >( this ) ) ).hasValue() )
        || ( mpStaticImpl->mbNameReplace && (aRet = ::cppu::queryInterface( rType, static_cast< XNameReplace* >( this ) ) ).hasValue() )
        || ( mpStaticImpl->mbNameContainer && (aRet = ::cppu::queryInterface( rType, static_cast< XNameContainer* >( this ) ) ).hasValue() )
        || ( mpStaticImpl->mbIndexAccess && (aRet = ::cppu::queryInterface( rType, static_cast< XIndexAccess* >( this ) ) ).hasValue() )
        || ( mpStaticImpl->mbIndexReplace && (aRet = ::cppu::queryInterface( rType, static_cast< XIndexReplace* >( this ) ) ).hasValue() )
        || ( mpStaticImpl->mbIndexContainer && (aRet = ::cppu::queryInterface( rType, static_cast< XIndexContainer* >( this ) ) ).hasValue() )
        || ( mpStaticImpl->mbEnumerationAccess && (aRet = ::cppu::queryInterface( rType, static_cast< XEnumerationAccess* >( this ) ) ).hasValue() )
        || ( mpStaticImpl->mbIdlArray && (aRet = ::cppu::queryInterface( rType, static_cast< XIdlArray* >( this ) ) ).hasValue() )
        || ( mpStaticImpl->mbUnoTunnel && (aRet = ::cppu::queryInterface( rType, static_cast< XUnoTunnel* >( this ) ) ).hasValue() );
    }
    return aRet;
}


//*** Implementation of ImplIntrospectionAdapter ***


// Methods from XPropertySet
Reference<XPropertySetInfo> ImplIntrospectionAccess::getPropertySetInfo()
{
    return static_cast<XPropertySetInfo *>(this);
}

void ImplIntrospectionAccess::setPropertyValue(const OUString& aPropertyName, const Any& aValue)
{
    mpStaticImpl->setPropertyValue( maInspectedObject, aPropertyName, aValue );
}

Any ImplIntrospectionAccess::getPropertyValue(const OUString& aPropertyName)
{
    return mpStaticImpl->getPropertyValue( maInspectedObject, aPropertyName );
}

void ImplIntrospectionAccess::addPropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener)
{
    if( mxIface.is() )
    {
        Reference<XPropertySet> xPropSet =
            Reference<XPropertySet>::query( mxIface );
        //Reference<XPropertySet> xPropSet( mxIface, USR_QUERY );
        if( xPropSet.is() )
            xPropSet->addPropertyChangeListener(aPropertyName, aListener);
    }
}

void ImplIntrospectionAccess::removePropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener)
{
    if( mxIface.is() )
    {
        Reference<XPropertySet> xPropSet =
            Reference<XPropertySet>::query( mxIface );
        //Reference<XPropertySet> xPropSet( mxIface, USR_QUERY );
        if( xPropSet.is() )
            xPropSet->removePropertyChangeListener(aPropertyName, aListener);
    }
}

void ImplIntrospectionAccess::addVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener)
{
    if( mxIface.is() )
    {
        Reference<XPropertySet> xPropSet =
            Reference<XPropertySet>::query( mxIface );
        //Reference<XPropertySet> xPropSet( mxIface, USR_QUERY );
        if( xPropSet.is() )
            xPropSet->addVetoableChangeListener(aPropertyName, aListener);
    }
}

void ImplIntrospectionAccess::removeVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener)
{
    if( mxIface.is() )
    {
        Reference<XPropertySet> xPropSet =
            Reference<XPropertySet>::query( mxIface );
        if( xPropSet.is() )
            xPropSet->removeVetoableChangeListener(aPropertyName, aListener);
    }
}


// Methods from XFastPropertySet
void ImplIntrospectionAccess::setFastPropertyValue(sal_Int32, const Any&)
{
}

Any ImplIntrospectionAccess::getFastPropertyValue(sal_Int32)
{
    return Any();
}

// Methods from XPropertySetInfo
Sequence< Property > ImplIntrospectionAccess::getProperties()
{
    return comphelper::containerToSequence(mpStaticImpl->getProperties());
}

Property ImplIntrospectionAccess::getPropertyByName(const OUString& Name)
{
    return getProperty( Name, PropertyConcept::ALL );
}

sal_Bool ImplIntrospectionAccess::hasPropertyByName(const OUString& Name)
{
    return hasProperty( Name, PropertyConcept::ALL );
}

// Methods from XElementAccess
Type ImplIntrospectionAccess::getElementType()
{
    return getXElementAccess()->getElementType();
}

sal_Bool ImplIntrospectionAccess::hasElements()
{
    return getXElementAccess()->hasElements();
}

// Methods from XNameAccess
Any ImplIntrospectionAccess::getByName(const OUString& Name)
{
    return getXNameAccess()->getByName( Name );
}

Sequence< OUString > ImplIntrospectionAccess::getElementNames()
{
    return getXNameAccess()->getElementNames();
}

sal_Bool ImplIntrospectionAccess::hasByName(const OUString& Name)
{
    return getXNameAccess()->hasByName( Name );
}

// Methods from XNameContainer
void ImplIntrospectionAccess::insertByName(const OUString& Name, const Any& Element)
{
    getXNameContainer()->insertByName( Name, Element );
}

void ImplIntrospectionAccess::replaceByName(const OUString& Name, const Any& Element)
{
    getXNameReplace()->replaceByName( Name, Element );
}

void ImplIntrospectionAccess::removeByName(const OUString& Name)
{
    getXNameContainer()->removeByName( Name );
}

// Methods from XIndexAccess
// Already in XNameAccess: virtual Reference<XIdlClass> getElementType() const
sal_Int32 ImplIntrospectionAccess::getCount()
{
    return getXIndexAccess()->getCount();
}

Any ImplIntrospectionAccess::getByIndex(sal_Int32 Index)
{
    return getXIndexAccess()->getByIndex( Index );
}

// Methods from XIndexContainer
void ImplIntrospectionAccess::insertByIndex(sal_Int32 Index, const Any& Element)
{
    getXIndexContainer()->insertByIndex( Index, Element );
}

void ImplIntrospectionAccess::replaceByIndex(sal_Int32 Index, const Any& Element)
{
    getXIndexReplace()->replaceByIndex( Index, Element );
}

void ImplIntrospectionAccess::removeByIndex(sal_Int32 Index)
{
    getXIndexContainer()->removeByIndex( Index );
}

// Methods from XEnumerationAccess
// Already in XNameAccess: virtual Reference<XIdlClass> getElementType() const;
Reference<XEnumeration> ImplIntrospectionAccess::createEnumeration()
{
    return getXEnumerationAccess()->createEnumeration();
}

// Methods from XIdlArray
void ImplIntrospectionAccess::realloc(Any& array, sal_Int32 length)
{
    getXIdlArray()->realloc( array, length );
}

sal_Int32 ImplIntrospectionAccess::getLen(const Any& array)
{
    return getXIdlArray()->getLen( array );
}

Any ImplIntrospectionAccess::get(const Any& array, sal_Int32 index)
{
    return getXIdlArray()->get( array, index );
}

void ImplIntrospectionAccess::set(Any& array, sal_Int32 index, const Any& value)
{
    getXIdlArray()->set( array, index, value );
}

// Methods from XUnoTunnel
sal_Int64 ImplIntrospectionAccess::getSomething( const Sequence< sal_Int8 >& aIdentifier )
{
    if (Reference<XUnoTunnel> xUnoTunnel{ mxIface, css::uno::UNO_QUERY })
        return xUnoTunnel->getSomething(aIdentifier);
    return 0;
}


//*** Implementation of ImplIntrospectionAccess ***

// Methods from XIntrospectionAccess
sal_Int32 ImplIntrospectionAccess::getSuppliedMethodConcepts()
{
    return    MethodConcept::DANGEROUS |
            PROPERTY |
            LISTENER |
            ENUMERATION |
            NAMECONTAINER |
            INDEXCONTAINER;
}

sal_Int32 ImplIntrospectionAccess::getSuppliedPropertyConcepts()
{
    return    PropertyConcept::DANGEROUS |
            PROPERTYSET |
            ATTRIBUTES |
            METHODS;
}

Property ImplIntrospectionAccess::getProperty(const OUString& Name, sal_Int32 PropertyConcepts)
{
    Property aRet;
    sal_Int32 i = mpStaticImpl->getPropertyIndex( Name );
    bool bFound = false;
    if( i != -1 )
    {
        sal_Int32 nConcept = mpStaticImpl->getPropertyConcepts()[ i ];
        if( (PropertyConcepts & nConcept) != 0 )
        {
            aRet = mpStaticImpl->getProperties()[ i ];
            bFound = true;
        }
    }
    if( !bFound )
        throw NoSuchElementException(Name);
    return aRet;
}

sal_Bool ImplIntrospectionAccess::hasProperty(const OUString& Name, sal_Int32 PropertyConcepts)
{
    sal_Int32 i = mpStaticImpl->getPropertyIndex( Name );
    bool bRet = false;
    if( i != -1 )
    {
        sal_Int32 nConcept = mpStaticImpl->getPropertyConcepts()[ i ];
        if( (PropertyConcepts & nConcept) != 0 )
            bRet = true;
    }
    return bRet;
}

Sequence< Property > ImplIntrospectionAccess::getProperties(sal_Int32 PropertyConcepts)
{
    // If all supported concepts are required, simply pass through the sequence
    sal_Int32 nAllSupportedMask =   PROPERTYSET |
                                    ATTRIBUTES |
                                    METHODS;
    if( ( PropertyConcepts & nAllSupportedMask ) == nAllSupportedMask )
    {
        return comphelper::containerToSequence(mpStaticImpl->getProperties());
    }

    // Same sequence as last time?
    if( mnLastPropertyConcept == PropertyConcepts )
    {
        return maLastPropertySeq;
    }

    // Number of properties to be delivered
    sal_Int32 nCount = 0;

    // There are currently no DANGEROUS properties
    // if( PropertyConcepts & DANGEROUS )
    //    nCount += mpStaticImpl->mnDangerousPropCount;
    if( PropertyConcepts & PROPERTYSET )
        nCount += mpStaticImpl->mnPropertySetPropCount;
    if( PropertyConcepts & ATTRIBUTES )
        nCount += mpStaticImpl->mnAttributePropCount;
    if( PropertyConcepts & METHODS )
        nCount += mpStaticImpl->mnMethodPropCount;

    // Realloc sequence according to the required number
    maLastPropertySeq.realloc( nCount );
    Property* pDestProps = maLastPropertySeq.getArray();

    // Go through all the properties and apply according to the concept
    const std::vector<Property>&  rPropSeq = mpStaticImpl->getProperties();
    const std::vector<sal_Int32>& rConcepts = mpStaticImpl->getPropertyConcepts();
    sal_Int32 nLen = static_cast<sal_Int32>(rPropSeq.size());

    sal_Int32 iDest = 0;
    for( sal_Int32 i = 0 ; i < nLen ; i++ )
    {
        sal_Int32 nConcept = rConcepts[ i ];
        if( nConcept & PropertyConcepts )
            pDestProps[ iDest++ ] = rPropSeq[ i ];
    }

    // Remember PropertyConcept representing maLastPropertySeq
    mnLastPropertyConcept = PropertyConcepts;

    // Supply assembled Sequence
    return maLastPropertySeq;
}

Reference<XIdlMethod> ImplIntrospectionAccess::getMethod(const OUString& Name, sal_Int32 MethodConcepts)
{
    Reference<XIdlMethod> xRet;
    sal_Int32 i = mpStaticImpl->getMethodIndex( Name );
    if( i != -1 )
    {

        sal_Int32 nConcept = mpStaticImpl->getMethodConcepts()[ i ];
        if( (MethodConcepts & nConcept) != 0 )
        {
            xRet = mpStaticImpl->getMethods()[i];
        }
    }
    if( !xRet.is() )
        throw NoSuchMethodException(Name);
    return xRet;
}

sal_Bool ImplIntrospectionAccess::hasMethod(const OUString& Name, sal_Int32 MethodConcepts)
{
    sal_Int32 i = mpStaticImpl->getMethodIndex( Name );
    bool bRet = false;
    if( i != -1 )
    {
        sal_Int32 nConcept = mpStaticImpl->getMethodConcepts()[ i ];
        if( (MethodConcepts & nConcept) != 0 )
            bRet = true;
    }
    return bRet;
}

Sequence< Reference<XIdlMethod> > ImplIntrospectionAccess::getMethods(sal_Int32 MethodConcepts)
{
    // If all supported concepts are required, simply pass through the sequence
    sal_Int32 nAllSupportedMask =   MethodConcept::DANGEROUS |
                                    PROPERTY |
                                    LISTENER |
                                    ENUMERATION |
                                    NAMECONTAINER |
                                    INDEXCONTAINER |
                                    MethodConcept_NORMAL_IMPL;
    if( ( MethodConcepts & nAllSupportedMask ) == nAllSupportedMask )
    {
        return comphelper::containerToSequence(mpStaticImpl->getMethods());
    }

    // Same sequence as last time?
    if( mnLastMethodConcept == MethodConcepts )
    {
        return maLastMethodSeq;
    }

    // Get method sequences
    const std::vector< Reference<XIdlMethod> >& aMethodSeq = mpStaticImpl->getMethods();
    sal_Int32 nLen = static_cast<sal_Int32>(aMethodSeq.size());

    // Realloc sequence according to the required number
    // Unlike Properties, the number can not be determined by counters in
    // inspect() beforehand, since methods can belong to several concepts
    maLastMethodSeq.realloc( nLen );
    Reference<XIdlMethod>* pDestMethods = maLastMethodSeq.getArray();

    // Go through all the methods and apply according to the concept
    sal_Int32 iDest = 0;
    for( sal_Int32 i = 0 ; i < nLen ; i++ )
    {
        sal_Int32 nConcept = mpStaticImpl->getMethodConcepts()[ i ];
        if( nConcept & MethodConcepts )
            pDestMethods[ iDest++ ] = aMethodSeq[ i ];
    }

    // Bring to the correct length
    maLastMethodSeq.realloc( iDest );

    // Remember MethodConcept representing maLastMethodSeq
    mnLastMethodConcept = MethodConcepts;

    // Supply assembled Sequence
    return maLastMethodSeq;
}

Sequence< Type > ImplIntrospectionAccess::getSupportedListeners()
{
    return comphelper::containerToSequence(mpStaticImpl->getSupportedListeners());
}

Reference<XInterface> SAL_CALL ImplIntrospectionAccess::queryAdapter( const Type& rType )
{
    Reference<XInterface> xRet;
    if(    rType == cppu::UnoType<XInterface>::get()
        || rType == cppu::UnoType<XPropertySet>::get()
        || rType == cppu::UnoType<XFastPropertySet>::get()
        || rType == cppu::UnoType<XPropertySetInfo>::get()
        || rType == cppu::UnoType<XElementAccess>::get()
        || rType == cppu::UnoType<XNameAccess>::get()
        || rType == cppu::UnoType<XNameReplace>::get()
        || rType == cppu::UnoType<XNameContainer>::get()
        || rType == cppu::UnoType<XIndexAccess>::get()
        || rType == cppu::UnoType<XIndexReplace>::get()
        || rType == cppu::UnoType<XIndexContainer>::get()
        || rType == cppu::UnoType<XEnumerationAccess>::get()
        || rType == cppu::UnoType<XIdlArray>::get()
        || rType == cppu::UnoType<XUnoTunnel>::get() )
    {
        queryInterface( rType ) >>= xRet;
    }
    return xRet;
}

// Methods from XMaterialHolder
Any ImplIntrospectionAccess::getMaterial()
{
    return maInspectedObject;
}

// Methods from XExactName
OUString ImplIntrospectionAccess::getExactName( const OUString& rApproximateName )
{
    OUString aRetStr;
    LowerToExactNameMap::iterator aIt =
        mpStaticImpl->maLowerToExactNameMap.find( rApproximateName.toAsciiLowerCase() );
    if (aIt != mpStaticImpl->maLowerToExactNameMap.end())
        aRetStr = (*aIt).second;
    return aRetStr;
}

struct TypeKey {
    TypeKey(
        css::uno::Reference<css::beans::XPropertySetInfo> theProperties,
        std::vector<css::uno::Type> const & theTypes):
        properties(std::move(theProperties))
    {
        //TODO: Could even sort the types lexicographically first, to increase
        // the chance of matches between different implementations' getTypes(),
        // but the old scheme of using getImplementationId() would have missed
        // those matches, too:
        OUStringBuffer b(static_cast<int>(theTypes.size() * 64));
        for (const css::uno::Type& rType : theTypes) {
            b.append(rType.getTypeName()
                + "*"); // arbitrary delimiter not used by type grammar
        }
        types = b.makeStringAndClear();
    }

    css::uno::Reference<css::beans::XPropertySetInfo> properties;
    OUString types;
};

struct TypeKeyLess {
    bool operator ()(TypeKey const & key1, TypeKey const & key2) const {
        if (key1.properties.get() < key2.properties.get()) {
            return true;
        }
        if (key1.properties.get() > key2.properties.get()) {
            return false;
        }
        return key1.types < key2.types;
    }
};

template<typename Key, typename Less> class Cache {
public:
    rtl::Reference<IntrospectionAccessStatic_Impl> find(Key const & key) const {
        typename Map::const_iterator i(map_.find(key));
        if (i == map_.end()) {
            return rtl::Reference<IntrospectionAccessStatic_Impl>();
        } else {
            if (i->second.hits < std::numeric_limits<unsigned>::max()) {
                ++i->second.hits;
            }
            assert(i->second.access.is());
            return i->second.access;
        }
    }

    void insert(
        Key const & key,
        rtl::Reference<IntrospectionAccessStatic_Impl> const & access)
    {
        assert(access.is());
        typename Map::size_type const MAX = 100;
        assert(map_.size() <= MAX);
        if (map_.size() == MAX) {
            typename Map::iterator del = std::min_element(map_.begin(), map_.end(),
                [](const typename Map::value_type& a, const typename Map::value_type& b) {
                    return a.second.hits < b.second.hits;
                });
            map_.erase(del);
        }
        bool ins = map_.emplace(key, Data(access)).second;
        assert(ins); (void)ins;
    }

    void clear() { map_.clear(); }

private:
    struct Data {
        explicit Data(
            rtl::Reference<IntrospectionAccessStatic_Impl> theAccess):
            access(std::move(theAccess)), hits(1)
        {}

        rtl::Reference<IntrospectionAccessStatic_Impl> access;
        mutable unsigned hits;
    };

    typedef std::map<Key, Data, Less> Map;

    Map map_;
};

typedef
    cppu::WeakComponentImplHelper<
        css::lang::XServiceInfo, css::beans::XIntrospection>
    Implementation_Base;

class Implementation: private cppu::BaseMutex, public Implementation_Base {
public:
    explicit Implementation(
        css::uno::Reference<css::uno::XComponentContext> const & context):
        Implementation_Base(m_aMutex),
        reflection_(css::reflection::theCoreReflection::get(context))
    {}

private:
    virtual void SAL_CALL disposing() override {
        osl::MutexGuard g(m_aMutex);
        reflection_.clear();
        typeCache_.clear();
    }

    virtual OUString SAL_CALL getImplementationName() override
    { return u"com.sun.star.comp.stoc.Introspection"_ustr; }

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

    virtual css::uno::Sequence<OUString> SAL_CALL
    getSupportedServiceNames() override
    {
        Sequence<OUString> s { u"com.sun.star.beans.Introspection"_ustr };
        return s;
    }

    virtual css::uno::Reference<css::beans::XIntrospectionAccess> SAL_CALL
    inspect(css::uno::Any const & aObject) override;

    css::uno::Reference<css::reflection::XIdlReflection> reflection_;
    Cache<TypeKey, TypeKeyLess> typeCache_;
};

css::uno::Reference<css::beans::XIntrospectionAccess> Implementation::inspect(
    css::uno::Any const & aObject)
{
    css::uno::Reference<css::reflection::XIdlReflection> reflection;
    {
        osl::MutexGuard g(m_aMutex);
        if (rBHelper.bDisposed || rBHelper.bInDispose) {
            throw css::lang::DisposedException(
                getImplementationName(), getXWeak());
        }
        reflection = reflection_;
    }
    css::uno::Any aToInspectObj;
    css::uno::Type t;
    if (aObject >>= t) {
        css::uno::Reference<css::reflection::XIdlClass> c(
            reflection->forName(t.getTypeName()));
        if (!c.is()) {
            SAL_WARN("stoc""cannot reflect type " << t.getTypeName());
            return css::uno::Reference<css::beans::XIntrospectionAccess>();
        }
        aToInspectObj <<= c;
    } else {
        aToInspectObj = aObject;
    }

    // Examine object
    TypeClass eType = aToInspectObj.getValueTypeClass();
    if( eType != TypeClass_INTERFACE && eType != TypeClass_STRUCT  && eType != TypeClass_EXCEPTION )
        return css::uno::Reference<css::beans::XIntrospectionAccess>();

    ifauto x = o3tl::tryAccess<Reference<XInterface>>(aToInspectObj) )
    {
        if( !x->is() )
            return css::uno::Reference<css::beans::XIntrospectionAccess>();
    }

    // Pointer to possibly needed new IntrospectionAccessStatic_Impl instance
    rtl::Reference< IntrospectionAccessStatic_Impl > pAccess;

    // Check: Is a matching access object already cached?
    std::vector< Reference<XIdlClass> >    SupportedClassSeq;
    std::vector< Type >                    SupportedTypesSeq;
    Reference<XTypeProvider>               xTypeProvider;
    Reference<XPropertySetInfo>            xPropSetInfo;
    Reference<XPropertySet>                xPropSet;

    // Look for interfaces XTypeProvider and PropertySet
    if( eType == TypeClass_INTERFACE )
    {
        xTypeProvider.set( aToInspectObj, UNO_QUERY );
        if( xTypeProvider.is() )
        {
            SupportedTypesSeq = comphelper::sequenceToContainer<std::vector<Type>>(xTypeProvider->getTypes());
        } else {
            SAL_WARN(
                "stoc",
                "object of type \"" << aToInspectObj.getValueTypeName()
                    << "\" lacks XTypeProvider");
            SupportedTypesSeq = { aToInspectObj.getValueType() };
        }
        // Now try to get the PropertySetInfo
        xPropSet.set( aToInspectObj, UNO_QUERY );
        if( xPropSet.is() )
            xPropSetInfo = xPropSet->getPropertySetInfo();

    } else {
        SupportedTypesSeq = { aToInspectObj.getValueType() };
    }

    {
        osl::MutexGuard g(m_aMutex);
        if (rBHelper.bDisposed || rBHelper.bInDispose) {
            throw css::lang::DisposedException(
                getImplementationName(), getXWeak());
        }
        TypeKey key(xPropSetInfo, SupportedTypesSeq);
        pAccess = typeCache_.find(key);
        if (pAccess.is()) {
            return new ImplIntrospectionAccess(aToInspectObj, pAccess);
        }
        pAccess = new IntrospectionAccessStatic_Impl(reflection);
        typeCache_.insert(key, pAccess);
    }

    // No access cached -> create new
    std::vector<Property>& rAllPropArray = pAccess->maAllPropertySeq;
    std::vector<Reference<XInterface>>& rInterfaces1 = pAccess->aInterfaceSeq1;
    std::vector<Reference<XInterface>>& rInterfaces2 = pAccess->aInterfaceSeq2;
    std::vector<sal_Int16>& rMapTypeArray = pAccess->maMapTypeSeq;
    std::vector<sal_Int32>& rPropertyConceptArray = pAccess->maPropertyConceptSeq;

    // References to important data from pAccess
    sal_Int32& rPropCount = pAccess->mnPropCount;
    IntrospectionNameMap& rPropNameMap = pAccess->maPropertyNameMap;
    IntrospectionNameMap& rMethodNameMap = pAccess->maMethodNameMap;
    LowerToExactNameMap& rLowerToExactNameMap = pAccess->maLowerToExactNameMap;


    //*** Perform analysis ***

    if( eType == TypeClass_INTERFACE )
    {
        size_t nTypeCount = SupportedTypesSeq.size();
        if( nTypeCount )
        {
            SupportedClassSeq.resize( nTypeCount );

            for( size_t i = 0 ; i < nTypeCount ; i++ )
                SupportedClassSeq[i] = reflection->forName( SupportedTypesSeq[i].getTypeName() );
        }

        // First look for particular interfaces that are of particular
        // importance to the introspection

        // Is XPropertySet present?
        if( xPropSet.is() && xPropSetInfo.is() )
        {
            // Is there also a FastPropertySet?
            Reference<XFastPropertySet> xDummy( aToInspectObj, UNO_QUERY );
            bool bFast = pAccess->mbFastPropSet = xDummy.is();

            Sequence<Property> aPropSeq = xPropSetInfo->getProperties();
            const Property* pProps = aPropSeq.getConstArray();
            sal_Int32 nLen = aPropSeq.getLength();

            // For a FastPropertySet we must remember the original handles
            if( bFast )
                pAccess->mpOrgPropertyHandleArray.reset( new sal_Int32[ nLen ] );

            for( sal_Int32 i = 0 ; i < nLen ; i++ )
            {
                // Put property in its own list
                pAccess->checkPropertyArraysSize( rPropCount );
                Property& rProp = rAllPropArray[ rPropCount ];
                rProp = pProps[ i ];

                if( bFast )
                    pAccess->mpOrgPropertyHandleArray[ i ] = rProp.Handle;

                // Enter PropCount as a handle for its own FastPropertySet
                rProp.Handle = rPropCount;

                // Remember type of property
                rMapTypeArray[ rPropCount ] = MAP_PROPERTY_SET;
                rPropertyConceptArray[ rPropCount ] = PROPERTYSET;
                pAccess->mnPropertySetPropCount++;

                // Enter name in hash table if not already known
                OUString aPropName = rProp.Name;

                // Do we already have the name?
                IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName );
                if( aIt == rPropNameMap.end() )
                {
                    // New entry in the hash table
                    rPropNameMap[ aPropName ] = rPropCount;

                    // Maintain table for XExactName
                    rLowerToExactNameMap[ aPropName.toAsciiLowerCase() ] = aPropName;
                }
                else
                {
                    SAL_WARN( "stoc""Introspection: Property \"" <<
                        aPropName << "\" found more than once in PropertySet" );
                }

                // Adjust count
                rPropCount++;
            }
        }

        // Indices in the export table
        sal_Int32 iAllExportedMethod = 0;
        sal_Int32 iAllSupportedListener = 0;

        std::set<OUString> seen;

        // Flag, whether XInterface methods should be recorded
        // (this must be done only once, allowed initially)
        bool bXInterfaceIsInvalid = false;

        // Flag whether the XInterface methods have already been recorded. If
        // sal_True, bXInterfaceIsInvalid is activated at the end of the interface
        // loop, and XInterface methods are cut off thereafter.
        bool bFoundXInterface = false;

        size_t nClassCount = SupportedClassSeq.size();
        for( size_t nIdx = 0 ; nIdx < nClassCount; nIdx++ )
        {
            Reference<XIdlClass> xImplClass2 = SupportedClassSeq[nIdx];
            while( xImplClass2.is() )
            {
                // Fetch interfaces from the implementation
                Sequence< Reference<XIdlClass> > aClassSeq = xImplClass2->getInterfaces();
                sal_Int32 nIfaceCount = aClassSeq.getLength();

                aClassSeq.realloc( nIfaceCount + 1 );
                aClassSeq.getArray()[ nIfaceCount ] = xImplClass2;

                for (const Reference<XIdlClass>& rxIfaceClass : aClassSeq)
                {
                    if (!seen.insert(rxIfaceClass->getName()).second) {
                        continue;
                    }

                    // 2. Register fields as properties

                    // Get fields
                    const Sequence< Reference<XIdlField> > fields = rxIfaceClass->getFields();

                    forconst Reference<XIdlField>& xField : fields )
                    {
                        Reference<XIdlClass> xPropType = xField->getType();

                        // Is the property sequence big enough?
                        pAccess->checkPropertyArraysSize( rPropCount );

                        // Enter in own property array
                        Property& rProp = rAllPropArray[ rPropCount ];
                        rProp.Name = xField->getName();
                        rProp.Handle = rPropCount;
                        rProp.Type = Type(xPropType->getTypeClass(), xPropType->getName());
                        FieldAccessMode eAccessMode = xField->getAccessMode();
                        rProp.Attributes = (eAccessMode == FieldAccessMode_READONLY ||
                                            eAccessMode == FieldAccessMode_CONST)
                            ? READONLY : 0;

                        // Enter name in hash table
                        OUString aPropName = rProp.Name;

                        // Do we have the name already?
                        IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName );
                        if (aIt != rPropNameMap.end())
                            continue;

                        // New entry in the hash table
                        rPropNameMap[ aPropName ] = rPropCount;

                        // Maintain table for XExactName
                        rLowerToExactNameMap[ aPropName.toAsciiLowerCase() ] = aPropName;

                        // Remember field
                        IntrospectionAccessStatic_Impl::checkInterfaceArraySize( pAccess->aInterfaceSeq1,
                                                          rInterfaces1, rPropCount );
                        rInterfaces1[ rPropCount ] = xField;

                        // Remember type of property
                        rMapTypeArray[ rPropCount ] = MAP_FIELD;
                        rPropertyConceptArray[ rPropCount ] = ATTRIBUTES;
                        pAccess->mnAttributePropCount++;

                        // Adjust count
                        rPropCount++;
                    }


                    // 3. Methods

                    // Get and remember all methods
                    Sequence< Reference<XIdlMethod> > methods = rxIfaceClass->getMethods();
                    const Reference<XIdlMethod>* pSourceMethods = methods.getConstArray();
                    sal_Int32 nSourceMethodCount = methods.getLength();

                    // 3. a) Search get/set and listener methods

                    // Create field for information about the methods, so that methods which are not
                    // related to properties or listeners can easily be found later.
                    // New: initialise MethodConceptArray
                    enum MethodType
                    {
                        STANDARD_METHOD,            // normal method, not related to properties or listeners
                        GETSET_METHOD,                // belongs to a get/set property
                        ADD_LISTENER_METHOD,        // add method of a listener interface
                        REMOVE_LISTENER_METHOD,        // remove method of a listener interface
                        INVALID_METHOD                // method whose class is not considered, e.g. XPropertySet
                    };
                    std::unique_ptr<MethodType[]> pMethodTypes( new MethodType[ nSourceMethodCount ] );
                    std::unique_ptr<sal_Int32[]> pLocalMethodConcepts( new sal_Int32[ nSourceMethodCount ] );
                    for( sal_Int32 i = 0 ; i < nSourceMethodCount ; i++ )
                    {
                        pMethodTypes[ i ] = STANDARD_METHOD;
                        pLocalMethodConcepts[ i ] = 0;
                    }

                    for( sal_Int32 i = 0 ; i < nSourceMethodCount ; i++ )
                    {
                        // Address method
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=92 H=96 G=93

¤ Dauer der Verarbeitung: 0.20 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge