/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_cppuhelper.hxx"
#include <osl/diagnose.h>
#include <osl/mutex.hxx>
#include <cppuhelper/weak.hxx>
#include <cppuhelper/component.hxx>
#include <cppuhelper/factory.hxx>
#ifndef _CPPUHELPER_IMPLBASE3_HXX
#include <cppuhelper/implbase3.hxx>
#endif
#include <cppuhelper/typeprovider.hxx>
#include <rtl/unload.h>

#include "cppuhelper/propshlp.hxx"

#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#include <com/sun/star/lang/XSingleComponentFactory.hpp>
#include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/loader/XImplementationLoader.hpp>
#include <com/sun/star/lang/XComponent.hpp>
#include <com/sun/star/lang/IllegalArgumentException.hpp>
#include <com/sun/star/uno/XUnloadingPreference.hpp>
#include "com/sun/star/beans/PropertyAttribute.hpp"

#include <memory>

#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )


using namespace osl;
using namespace rtl;
using namespace com::sun::star;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::loader;
using namespace com::sun::star::registry;

namespace cppu
{

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
class OSingleFactoryHelper
	: public XServiceInfo
	, public XSingleServiceFactory
    , public lang::XSingleComponentFactory
	, public XUnloadingPreference
{
public:
	OSingleFactoryHelper(
		const Reference<XMultiServiceFactory > & rServiceManager,
		const OUString & rImplementationName_,
		ComponentInstantiation pCreateFunction_,
        ComponentFactoryFunc fptr,
		const Sequence< OUString > * pServiceNames_ )
		SAL_THROW( () )
		: xSMgr( rServiceManager )
		, pCreateFunction( pCreateFunction_ )
        , m_fptr( fptr )
		, aImplementationName( rImplementationName_ )
		{
			if( pServiceNames_ )
				aServiceNames = *pServiceNames_;
		}

	// old function, only for backward compatibility
	OSingleFactoryHelper(
		const Reference<XMultiServiceFactory > & rServiceManager,
		const OUString & rImplementationName_ )
		SAL_THROW( () )
		: xSMgr( rServiceManager )
		, pCreateFunction( NULL )
        , m_fptr( 0 )
		, aImplementationName( rImplementationName_ )
		{}

    virtual ~OSingleFactoryHelper();

	// XInterface
	Any SAL_CALL queryInterface( const Type & rType )
		throw(::com::sun::star::uno::RuntimeException);

	// XSingleServiceFactory
    Reference<XInterface > SAL_CALL createInstance()
		throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
    virtual Reference<XInterface > SAL_CALL createInstanceWithArguments(const Sequence<Any>& Arguments)
		throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
    // XSingleComponentFactory
    virtual Reference< XInterface > SAL_CALL createInstanceWithContext(
        Reference< XComponentContext > const & xContext )
        throw (Exception, RuntimeException);
    virtual Reference< XInterface > SAL_CALL createInstanceWithArgumentsAndContext(
        Sequence< Any > const & rArguments,
        Reference< XComponentContext > const & xContext )
        throw (Exception, RuntimeException);

	// XServiceInfo
	OUString SAL_CALL getImplementationName()
		throw(::com::sun::star::uno::RuntimeException);
    sal_Bool SAL_CALL supportsService(const OUString& ServiceName)
		throw(::com::sun::star::uno::RuntimeException);
    Sequence< OUString > SAL_CALL getSupportedServiceNames(void)
		throw(::com::sun::star::uno::RuntimeException);

protected:
	/**
	 * Create an instance specified by the factory. The one instance logic is implemented
	 * in the createInstance and createInstanceWithArguments methods.
	 * @return the newly created instance. Do not return a previous (one instance) instance.
	 */
	virtual Reference<XInterface >	createInstanceEveryTime(
        Reference< XComponentContext > const & xContext )
		throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);

	Reference<XMultiServiceFactory > xSMgr;
	ComponentInstantiation			 pCreateFunction;
    ComponentFactoryFunc             m_fptr;
	Sequence< OUString >			 aServiceNames;
	OUString						 aImplementationName;
};
OSingleFactoryHelper::~OSingleFactoryHelper()
{
}


//-----------------------------------------------------------------------------
Any OSingleFactoryHelper::queryInterface( const Type & rType )
	throw(::com::sun::star::uno::RuntimeException)
{
    return ::cppu::queryInterface(
        rType,
        static_cast< XSingleComponentFactory * >( this ),
        static_cast< XSingleServiceFactory * >( this ),
        static_cast< XServiceInfo * >( this ) ,
        static_cast< XUnloadingPreference * >( this ));
}

// OSingleFactoryHelper
Reference<XInterface > OSingleFactoryHelper::createInstanceEveryTime(
    Reference< XComponentContext > const & xContext )
	throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
{
    if (m_fptr)
    {
        return (*m_fptr)( xContext );
    }
    else if( pCreateFunction )
    {
        if (xContext.is())
        {
            Reference< lang::XMultiServiceFactory > xContextMgr(
                xContext->getServiceManager(), UNO_QUERY );
            if (xContextMgr.is())
                return (*pCreateFunction)( xContextMgr );
        }
        return (*pCreateFunction)( xSMgr );
    }
	else
    {
		return Reference< XInterface >();
    }
}

// XSingleServiceFactory
Reference<XInterface > OSingleFactoryHelper::createInstance()
	throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
{
    return createInstanceWithContext( Reference< XComponentContext >() );
}

// XSingleServiceFactory
Reference<XInterface > OSingleFactoryHelper::createInstanceWithArguments(
	const Sequence<Any>& Arguments )
	throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
{
    return createInstanceWithArgumentsAndContext(
        Arguments, Reference< XComponentContext >() );
}

// XSingleComponentFactory
//__________________________________________________________________________________________________
Reference< XInterface > OSingleFactoryHelper::createInstanceWithContext(
    Reference< XComponentContext > const & xContext )
    throw (Exception, RuntimeException)
{
    return createInstanceEveryTime( xContext );
}
//__________________________________________________________________________________________________
Reference< XInterface > OSingleFactoryHelper::createInstanceWithArgumentsAndContext(
    Sequence< Any > const & rArguments,
    Reference< XComponentContext > const & xContext )
    throw (Exception, RuntimeException)
{
	Reference< XInterface > xRet( createInstanceWithContext( xContext ) );

	Reference< lang::XInitialization > xInit( xRet, UNO_QUERY );
    // always call initialize, even if there are no arguments.
    // #i63511# / 2006-03-27 / frank.schoenheit@sun.com
	if (xInit.is())
    {
		xInit->initialize( rArguments );
    }
	else
    {
		if ( rArguments.getLength() )
        {
            // dispose the here created UNO object before throwing out exception
            // to avoid risk of memory leaks #i113722#
            Reference<XComponent> xComp( xRet, UNO_QUERY );
            if (xComp.is())
                xComp->dispose();

		    throw lang::IllegalArgumentException(
                OUString( RTL_CONSTASCII_USTRINGPARAM("cannot pass arguments to component => no XInitialization implemented!") ),
                Reference< XInterface >(), 0 );
		}
    }

	return xRet;
}

// XServiceInfo
OUString OSingleFactoryHelper::getImplementationName()
	throw(::com::sun::star::uno::RuntimeException)
{
	return aImplementationName;
}

// XServiceInfo
sal_Bool OSingleFactoryHelper::supportsService(
    const OUString& ServiceName )
	throw(::com::sun::star::uno::RuntimeException)
{
	Sequence< OUString > seqServices = getSupportedServiceNames();
	const OUString * pServices = seqServices.getConstArray();
	for( sal_Int32 i = 0; i < seqServices.getLength(); i++ )
		if( pServices[i] == ServiceName )
			return sal_True;

	return sal_False;
}

// XServiceInfo
Sequence< OUString > OSingleFactoryHelper::getSupportedServiceNames(void)
	throw(::com::sun::star::uno::RuntimeException)
{
	return aServiceNames;
}


//----------------------------------------------------------------------
//----------------------------------------------------------------------
//----------------------------------------------------------------------
struct OFactoryComponentHelper_Mutex
{
	Mutex	aMutex;
};

class OFactoryComponentHelper
	: public OFactoryComponentHelper_Mutex
	, public OComponentHelper
	, public OSingleFactoryHelper
{
public:
	OFactoryComponentHelper(
		const Reference<XMultiServiceFactory > & rServiceManager,
		const OUString & rImplementationName_,
		ComponentInstantiation pCreateFunction_,
        ComponentFactoryFunc fptr,
		const Sequence< OUString > * pServiceNames_,
		sal_Bool bOneInstance_ = sal_False )
		SAL_THROW( () )
		: OComponentHelper( aMutex )
		, OSingleFactoryHelper( rServiceManager, rImplementationName_, pCreateFunction_, fptr, pServiceNames_ )
		, bOneInstance( bOneInstance_ )
		, pModuleCount(0)
		{
		}

	// Used by the createXXXFactory functions. The argument pModCount is used to  prevent the unloading of the module
	// which contains pCreateFunction_
	OFactoryComponentHelper(
		const Reference<XMultiServiceFactory > & rServiceManager,
		const OUString & rImplementationName_,
		ComponentInstantiation pCreateFunction_,
        ComponentFactoryFunc fptr,
		const Sequence< OUString > * pServiceNames_,
		rtl_ModuleCount * pModCount,
		sal_Bool bOneInstance_ = sal_False )
		SAL_THROW( () )
		: OComponentHelper( aMutex )
		, OSingleFactoryHelper( rServiceManager, rImplementationName_, pCreateFunction_, fptr, pServiceNames_ )
		, bOneInstance( bOneInstance_ )
		, pModuleCount(pModCount)
		{
			if(pModuleCount)
				pModuleCount->acquire( pModuleCount);
		}

	// old function, only for backward compatibility
	OFactoryComponentHelper(
		const Reference<XMultiServiceFactory > & rServiceManager,
		const OUString & rImplementationName_,
		sal_Bool bOneInstance_ = sal_False )
		SAL_THROW( () )
		: OComponentHelper( aMutex )
		, OSingleFactoryHelper( rServiceManager, rImplementationName_ )
		, bOneInstance( bOneInstance_ )
		, pModuleCount(0)
		{
		}

	~OFactoryComponentHelper()
	{
		if(pModuleCount)
			pModuleCount->release( pModuleCount);
	}

	// XInterface
	Any SAL_CALL queryInterface( const Type & rType )
		throw(::com::sun::star::uno::RuntimeException);
	void SAL_CALL acquire() throw()
		{ OComponentHelper::acquire(); }
	void SAL_CALL release() throw()
		{ OComponentHelper::release(); }

	// XSingleServiceFactory
    Reference<XInterface > SAL_CALL createInstance()
		throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
	Reference<XInterface > SAL_CALL createInstanceWithArguments( const Sequence<Any>& Arguments )
		throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
    // XSingleComponentFactory
    virtual Reference< XInterface > SAL_CALL createInstanceWithContext(
        Reference< XComponentContext > const & xContext )
        throw (Exception, RuntimeException);
    virtual Reference< XInterface > SAL_CALL createInstanceWithArgumentsAndContext(
        Sequence< Any > const & rArguments,
        Reference< XComponentContext > const & xContext )
        throw (Exception, RuntimeException);

	// XTypeProvider
	virtual Sequence< Type > SAL_CALL getTypes() throw (::com::sun::star::uno::RuntimeException);
	virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() throw(::com::sun::star::uno::RuntimeException);

	// XAggregation
	Any SAL_CALL queryAggregation( const Type & rType )
		throw(::com::sun::star::uno::RuntimeException);

	// XUnloadingPreference
	virtual sal_Bool SAL_CALL releaseOnNotification()
		throw(::com::sun::star::uno::RuntimeException);

	// OComponentHelper
	void SAL_CALL dispose() throw(::com::sun::star::uno::RuntimeException);

private:
	Reference<XInterface >	xTheInstance;
	sal_Bool				bOneInstance;
	rtl_ModuleCount	*		pModuleCount;
protected:
	// needed for implementing XUnloadingPreference in inheriting classes
	sal_Bool isOneInstance() {return bOneInstance;}
	sal_Bool isInstance() {return xTheInstance.is();}
};


Any SAL_CALL OFactoryComponentHelper::queryInterface( const Type & rType )
	throw(::com::sun::star::uno::RuntimeException)
{
	if( rType == ::getCppuType( (Reference<XUnloadingPreference>*)0))
	{
		return makeAny(
            Reference< XUnloadingPreference >(
                static_cast< XUnloadingPreference * >(this) ) );
	}
	return OComponentHelper::queryInterface( rType );
}

// XAggregation
Any OFactoryComponentHelper::queryAggregation( const Type & rType )
	throw(::com::sun::star::uno::RuntimeException)
{
	Any aRet( OComponentHelper::queryAggregation( rType ) );
	return (aRet.hasValue() ? aRet : OSingleFactoryHelper::queryInterface( rType ));
}

// XTypeProvider
Sequence< Type > OFactoryComponentHelper::getTypes()
	throw (::com::sun::star::uno::RuntimeException)
{
    Type ar[ 4 ];
    ar[ 0 ] = ::getCppuType( (const Reference< XSingleServiceFactory > *)0 );
    ar[ 1 ] = ::getCppuType( (const Reference< XServiceInfo > *)0 );
    ar[ 2 ] = ::getCppuType( (const Reference< XUnloadingPreference > *)0 );

    if (m_fptr)
        ar[ 3 ] = ::getCppuType( (const Reference< XSingleComponentFactory > *)0 );

    return Sequence< Type >( ar, m_fptr ? 4 : 3 );
}

Sequence< sal_Int8 > OFactoryComponentHelper::getImplementationId()
	throw (::com::sun::star::uno::RuntimeException)
{
	static OImplementationId * pId = 0;
	if (! pId)
	{
		MutexGuard aGuard( Mutex::getGlobalMutex() );
		if (! pId)
		{
			static OImplementationId aId;
			pId = &aId;
		}
	}
	return pId->getImplementationId();
}

// XSingleServiceFactory
Reference<XInterface > OFactoryComponentHelper::createInstance()
	throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
{
	if( bOneInstance )
	{
		if( !xTheInstance.is() )
        {
            MutexGuard aGuard( aMutex );
            if( !xTheInstance.is() )
                xTheInstance = OSingleFactoryHelper::createInstance();
        }
		return xTheInstance;
	}
	return OSingleFactoryHelper::createInstance();
}

Reference<XInterface > OFactoryComponentHelper::createInstanceWithArguments(
	const Sequence<Any>& Arguments )
	throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
{
	if( bOneInstance )
	{
		if( !xTheInstance.is() )
        {
            MutexGuard aGuard( aMutex );
//          OSL_ENSURE( !xTheInstance.is(), "### arguments will be ignored!" );
            if( !xTheInstance.is() )
                xTheInstance = OSingleFactoryHelper::createInstanceWithArguments( Arguments );
        }
        return xTheInstance;
	}
	return OSingleFactoryHelper::createInstanceWithArguments( Arguments );
}

// XSingleComponentFactory
//__________________________________________________________________________________________________
Reference< XInterface > OFactoryComponentHelper::createInstanceWithContext(
    Reference< XComponentContext > const & xContext )
    throw (Exception, RuntimeException)
{
	if( bOneInstance )
	{
		if( !xTheInstance.is() )
        {
            MutexGuard aGuard( aMutex );
//          OSL_ENSURE( !xTheInstance.is(), "### context will be ignored!" );
            if( !xTheInstance.is() )
                xTheInstance = OSingleFactoryHelper::createInstanceWithContext( xContext );
        }
		return xTheInstance;
	}
	return OSingleFactoryHelper::createInstanceWithContext( xContext );
}
//__________________________________________________________________________________________________
Reference< XInterface > OFactoryComponentHelper::createInstanceWithArgumentsAndContext(
    Sequence< Any > const & rArguments,
    Reference< XComponentContext > const & xContext )
    throw (Exception, RuntimeException)
{
	if( bOneInstance )
	{
		if( !xTheInstance.is() )
        {
            MutexGuard aGuard( aMutex );
//          OSL_ENSURE( !xTheInstance.is(), "### context and arguments will be ignored!" );
            if( !xTheInstance.is() )
                xTheInstance = OSingleFactoryHelper::createInstanceWithArgumentsAndContext( rArguments, xContext );
        }
		return xTheInstance;
	}
	return OSingleFactoryHelper::createInstanceWithArgumentsAndContext( rArguments, xContext );
}


// OComponentHelper
void OFactoryComponentHelper::dispose()
	throw(::com::sun::star::uno::RuntimeException)
{
	OComponentHelper::dispose();

	Reference<XInterface > x;
	{
		// do not delete in the guard section
		MutexGuard aGuard( aMutex );
		x = xTheInstance;
		xTheInstance = Reference<XInterface >();
	}
	// if it is a component call dispose at the component
	Reference<XComponent > xComp( x, UNO_QUERY );
	if( xComp.is() )
		xComp->dispose();
}

// XUnloadingPreference
// This class is used for single factories, component factories and
// one-instance factories. Depending on the usage this function has
// to return different values.
// one-instance factory: sal_False
// single factory: sal_True
// component factory: sal_True
sal_Bool SAL_CALL OFactoryComponentHelper::releaseOnNotification() throw(::com::sun::star::uno::RuntimeException)
{
	if( bOneInstance)
		return sal_False;
	return sal_True;
}


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
class ORegistryFactoryHelper : public OFactoryComponentHelper,
                               public OPropertySetHelper
    
{
public:
	ORegistryFactoryHelper(
		const Reference<XMultiServiceFactory > & rServiceManager,
		const OUString & rImplementationName_,
		const Reference<XRegistryKey > & xImplementationKey_,
		sal_Bool bOneInstance_ = sal_False ) SAL_THROW( () )
            : OFactoryComponentHelper(
                rServiceManager, rImplementationName_, 0, 0, 0, bOneInstance_ ),
              OPropertySetHelper( OComponentHelper::rBHelper ),
              xImplementationKey( xImplementationKey_ )
		{}
    
    // XInterface
    virtual Any SAL_CALL queryInterface( Type const & type )
        throw (RuntimeException);
    virtual void SAL_CALL acquire() throw ();
    virtual void SAL_CALL release() throw ();
    // XTypeProvider
    virtual Sequence< Type > SAL_CALL getTypes()
        throw (RuntimeException);
    // XPropertySet
    virtual Reference< beans::XPropertySetInfo > SAL_CALL getPropertySetInfo()
        throw (RuntimeException);

    // OPropertySetHelper
    virtual IPropertyArrayHelper & SAL_CALL getInfoHelper();
    virtual sal_Bool SAL_CALL convertFastPropertyValue(
        Any & rConvertedValue, Any & rOldValue,
        sal_Int32 nHandle, Any const & rValue )
        throw (lang::IllegalArgumentException);
    virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
        sal_Int32 nHandle, Any const & rValue )
        throw (Exception);
    using OPropertySetHelper::getFastPropertyValue;
    virtual void SAL_CALL getFastPropertyValue(
        Any & rValue, sal_Int32 nHandle ) const;
    
	// OSingleFactoryHelper
	Reference<XInterface > createInstanceEveryTime(
        Reference< XComponentContext > const & xContext )
		throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);

	// XSingleServiceFactory
	Reference<XInterface > SAL_CALL createInstanceWithArguments(const Sequence<Any>& Arguments)
		throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
    // XSingleComponentFactory
    Reference< XInterface > SAL_CALL createInstanceWithArgumentsAndContext(
        Sequence< Any > const & rArguments,
        Reference< XComponentContext > const & xContext )
        throw (Exception, RuntimeException);

	// XServiceInfo
    Sequence< OUString > SAL_CALL getSupportedServiceNames(void)
		throw(::com::sun::star::uno::RuntimeException);
	// XUnloadingPreference
	sal_Bool SAL_CALL releaseOnNotification()
		throw( RuntimeException);


private:
	Reference< XInterface > createModuleFactory()
		throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);

	/** The registry key of the implementation section */
	Reference<XRegistryKey >	xImplementationKey;
	/** The factory created with the loader. */
	Reference<XSingleComponentFactory >	xModuleFactory;
	Reference<XSingleServiceFactory >	xModuleFactoryDepr;
    Reference< beans::XPropertySetInfo > m_xInfo;
    ::std::auto_ptr< IPropertyArrayHelper > m_property_array_helper;
protected:
    using OPropertySetHelper::getTypes;
};

// XInterface
//______________________________________________________________________________
Any SAL_CALL ORegistryFactoryHelper::queryInterface(
    Type const & type ) throw (RuntimeException)
{
    Any ret( OFactoryComponentHelper::queryInterface( type ) );
    if (ret.hasValue())
        return ret;
    else
        return OPropertySetHelper::queryInterface( type );
}

//______________________________________________________________________________
void ORegistryFactoryHelper::acquire() throw ()
{
    OFactoryComponentHelper::acquire();
}

//______________________________________________________________________________
void ORegistryFactoryHelper::release() throw ()
{
    OFactoryComponentHelper::release();
}

// XTypeProvider
//______________________________________________________________________________
Sequence< Type > ORegistryFactoryHelper::getTypes() throw (RuntimeException)
{
    Sequence< Type > types( OFactoryComponentHelper::getTypes() );
    sal_Int32 pos = types.getLength();
    types.realloc( pos + 3 );
    Type * p = types.getArray();
    p[ pos++ ] = ::getCppuType(
        reinterpret_cast< Reference< beans::XMultiPropertySet > const * >(0) );
    p[ pos++ ] = ::getCppuType(
        reinterpret_cast< Reference< beans::XFastPropertySet > const * >(0) );
    p[ pos++ ] = ::getCppuType(
        reinterpret_cast< Reference< beans::XPropertySet > const * >(0) );
    return types;
}

// XPropertySet
//______________________________________________________________________________
Reference< beans::XPropertySetInfo >
ORegistryFactoryHelper::getPropertySetInfo() throw (RuntimeException)
{
    ::osl::MutexGuard guard( aMutex );
    if (! m_xInfo.is())
        m_xInfo = createPropertySetInfo( getInfoHelper() );
    return m_xInfo;
}

// OPropertySetHelper
//______________________________________________________________________________
IPropertyArrayHelper & ORegistryFactoryHelper::getInfoHelper()
{
    ::osl::MutexGuard guard( aMutex );
    if (m_property_array_helper.get() == 0)
    {
        beans::Property prop(
            OUSTR("ImplementationKey") /* name */,
            0 /* handle */,
            ::getCppuType( &xImplementationKey ),
            beans::PropertyAttribute::READONLY |
            beans::PropertyAttribute::OPTIONAL );
        m_property_array_helper.reset(
            new ::cppu::OPropertyArrayHelper( &prop, 1 ) );
    }
    return *m_property_array_helper.get();
}

//______________________________________________________________________________
sal_Bool ORegistryFactoryHelper::convertFastPropertyValue(
    Any &, Any &, sal_Int32, Any const & )
    throw (lang::IllegalArgumentException)
{
    OSL_ENSURE( 0, "unexpected!" );
    return false;
}

//______________________________________________________________________________
void ORegistryFactoryHelper::setFastPropertyValue_NoBroadcast(
    sal_Int32, Any const & )
    throw (Exception)
{
    throw beans::PropertyVetoException(
        OUSTR("unexpected: only readonly properties!"),
        static_cast< OWeakObject * >(this) );
}

//______________________________________________________________________________
void ORegistryFactoryHelper::getFastPropertyValue(
    Any & rValue, sal_Int32 nHandle ) const
{
    if (nHandle == 0)
    {
        rValue <<= xImplementationKey;
    }
    else
    {
        rValue.clear();
        throw beans::UnknownPropertyException(
            OUSTR("unknown property!"), static_cast< OWeakObject * >(
                const_cast< ORegistryFactoryHelper * >(this) ) );
    }
}

Reference<XInterface > ORegistryFactoryHelper::createInstanceEveryTime(
    Reference< XComponentContext > const & xContext )
	throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
{
	if( !xModuleFactory.is() && !xModuleFactoryDepr.is() )
	{
        Reference< XInterface > x( createModuleFactory() );
        if (x.is())
        {
            MutexGuard aGuard( aMutex );
            if( !xModuleFactory.is() && !xModuleFactoryDepr.is() )
            {
                xModuleFactory.set( x, UNO_QUERY );
                xModuleFactoryDepr.set( x, UNO_QUERY );
            }
        }
	}
	if( xModuleFactory.is() )
    {
		return xModuleFactory->createInstanceWithContext( xContext );
    }
    else if( xModuleFactoryDepr.is() )
    {
		return xModuleFactoryDepr->createInstance();
    }

	return Reference<XInterface >();
}

Reference<XInterface > SAL_CALL ORegistryFactoryHelper::createInstanceWithArguments(
    const Sequence<Any>& Arguments )
    throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
{
	if( !xModuleFactory.is() && !xModuleFactoryDepr.is() )
	{
        Reference< XInterface > x( createModuleFactory() );
        if (x.is())
        {
            MutexGuard aGuard( aMutex );
            if( !xModuleFactory.is() && !xModuleFactoryDepr.is() )
            {
                xModuleFactory.set( x, UNO_QUERY );
                xModuleFactoryDepr.set( x, UNO_QUERY );
            }
        }
	}
    if( xModuleFactoryDepr.is() )
    {
		return xModuleFactoryDepr->createInstanceWithArguments( Arguments );
    }
	else if( xModuleFactory.is() )
    {
#if OSL_DEBUG_LEVEL > 1
        OSL_TRACE( "### no context ORegistryFactoryHelper::createInstanceWithArgumentsAndContext()!\n" );
#endif
		return xModuleFactory->createInstanceWithArgumentsAndContext( Arguments, Reference< XComponentContext >() );
    }

	return Reference<XInterface >();
}

Reference< XInterface > ORegistryFactoryHelper::createInstanceWithArgumentsAndContext(
    Sequence< Any > const & rArguments,
    Reference< XComponentContext > const & xContext )
    throw (Exception, RuntimeException)
{
	if( !xModuleFactory.is() && !xModuleFactoryDepr.is() )
	{
        Reference< XInterface > x( createModuleFactory() );
        if (x.is())
        {
            MutexGuard aGuard( aMutex );
            if( !xModuleFactory.is() && !xModuleFactoryDepr.is() )
            {
                xModuleFactory.set( x, UNO_QUERY );
                xModuleFactoryDepr.set( x, UNO_QUERY );
            }
        }
	}
	if( xModuleFactory.is() )
    {
		return xModuleFactory->createInstanceWithArgumentsAndContext( rArguments, xContext );
    }
    else if( xModuleFactoryDepr.is() )
    {
#if OSL_DEBUG_LEVEL > 1
        if (xContext.is())
        {
            OSL_TRACE( "### ignoring context calling ORegistryFactoryHelper::createInstanceWithArgumentsAndContext()!\n" );
        }
#endif
		return xModuleFactoryDepr->createInstanceWithArguments( rArguments );
    }

	return Reference<XInterface >();
}


// OSingleFactoryHelper
Reference< XInterface > ORegistryFactoryHelper::createModuleFactory()
	throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
{
    OUString aActivatorUrl;
    OUString aActivatorName;
    OUString aLocation;

    Reference<XRegistryKey > xActivatorKey = xImplementationKey->openKey(
        OUString( RTL_CONSTASCII_USTRINGPARAM("/UNO/ACTIVATOR") ) );
    if( xActivatorKey.is() && xActivatorKey->getValueType() == RegistryValueType_ASCII )
    {
        aActivatorUrl = xActivatorKey->getAsciiValue();

        OUString tmpActivator(aActivatorUrl.getStr());
        sal_Int32 nIndex = 0;
        aActivatorName = tmpActivator.getToken(0, ':', nIndex );

        Reference<XRegistryKey > xLocationKey = xImplementationKey->openKey(
            OUString( RTL_CONSTASCII_USTRINGPARAM("/UNO/LOCATION") ) );
        if( xLocationKey.is() && xLocationKey->getValueType() == RegistryValueType_ASCII )
            aLocation = xLocationKey->getAsciiValue();
    }
    else
    {
        // old style"url"
        // the location of the program code of the implementation
        Reference<XRegistryKey > xLocationKey = xImplementationKey->openKey(
            OUString( RTL_CONSTASCII_USTRINGPARAM("/UNO/URL") ) );
        // is the the key of the right type ?
        if( xLocationKey.is() && xLocationKey->getValueType() == RegistryValueType_ASCII )
        {
            // one implementation found -> try to activate
            aLocation = xLocationKey->getAsciiValue();

            // search protocol delemitter
            sal_Int32 nPos = aLocation.indexOf(
                OUString( RTL_CONSTASCII_USTRINGPARAM("://") ) );
            if( nPos != -1 )
            {
                aActivatorName = aLocation.copy( 0, nPos );
                if( aActivatorName.compareToAscii( "java" ) == 0 )
                    aActivatorName = OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.loader.Java") );
                else if( aActivatorName.compareToAscii( "module" ) == 0 )
                    aActivatorName = OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.loader.SharedLibrary") );
                aLocation = aLocation.copy( nPos + 3 );
            }
        }
    }

	Reference< XInterface >	xFactory;
    if( aActivatorName.getLength() != 0 )
    {
        Reference<XInterface > x = xSMgr->createInstance( aActivatorName );
        Reference<XImplementationLoader > xLoader( x, UNO_QUERY );
        Reference<XInterface > xMF;
        if (xLoader.is())
        {
            xFactory = xLoader->activate( aImplementationName, aActivatorUrl, aLocation, xImplementationKey );
        }
    }
	return xFactory;
}

// XServiceInfo
Sequence< OUString > ORegistryFactoryHelper::getSupportedServiceNames(void)
	throw(::com::sun::star::uno::RuntimeException)
{
	MutexGuard aGuard( aMutex );
	if( aServiceNames.getLength() == 0 )
	{
		// not yet loaded
		try
		{
			Reference<XRegistryKey > xKey = xImplementationKey->openKey(
				OUString( RTL_CONSTASCII_USTRINGPARAM("UNO/SERVICES") ) );

			if (xKey.is())
			{
				// length of prefix. +1 for the '/' at the end
				sal_Int32 nPrefixLen = xKey->getKeyName().getLength() + 1;

				// Full qualified names like "IMPLEMENTATIONS/TEST/UNO/SERVICES/com.sun.star..."
				Sequence<OUString> seqKeys = xKey->getKeyNames();
				OUString* pKeys = seqKeys.getArray();
				for( sal_Int32 i = 0; i < seqKeys.getLength(); i++ )
					pKeys[i] = pKeys[i].copy(nPrefixLen);

				aServiceNames = seqKeys;
			}
		}
		catch (InvalidRegistryException &)
		{
		}
	}
	return aServiceNames;
}

sal_Bool SAL_CALL ORegistryFactoryHelper::releaseOnNotification() throw(::com::sun::star::uno::RuntimeException)
{
	sal_Bool retVal= sal_True;
	if( isOneInstance() && isInstance())
	{
		retVal= sal_False;
	}
	else if( ! isOneInstance())
	{
		// try to delegate
		if( xModuleFactory.is())
		{
			Reference<XUnloadingPreference> xunloading( xModuleFactory, UNO_QUERY);
			if( xunloading.is())
				retVal= xunloading->releaseOnNotification();
		}
		else if( xModuleFactoryDepr.is())
		{
			Reference<XUnloadingPreference> xunloading( xModuleFactoryDepr, UNO_QUERY);
			if( xunloading.is())
				retVal= xunloading->releaseOnNotification();
		}
	}
	return retVal;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

class OFactoryProxyHelper : public WeakImplHelper3< XServiceInfo, XSingleServiceFactory,
													XUnloadingPreference >
{
	Reference<XSingleServiceFactory >	xFactory;

public:

	OFactoryProxyHelper(
		const Reference<XMultiServiceFactory > & /*rServiceManager*/,
		const Reference<XSingleServiceFactory > & rFactory )
		SAL_THROW( () )
		: xFactory( rFactory )
		{}

	// XSingleServiceFactory
    Reference<XInterface > SAL_CALL createInstance()
		throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
    Reference<XInterface > SAL_CALL createInstanceWithArguments(const Sequence<Any>& Arguments)
		throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);

	// XServiceInfo
	OUString SAL_CALL getImplementationName()
		throw(::com::sun::star::uno::RuntimeException);
    sal_Bool SAL_CALL supportsService(const OUString& ServiceName)
		throw(::com::sun::star::uno::RuntimeException);
    Sequence< OUString > SAL_CALL getSupportedServiceNames(void)
		throw(::com::sun::star::uno::RuntimeException);
	//XUnloadingPreference
	sal_Bool SAL_CALL releaseOnNotification()
		throw(::com::sun::star::uno::RuntimeException);

};

// XSingleServiceFactory
Reference<XInterface > OFactoryProxyHelper::createInstance()
	throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
{
	return xFactory->createInstance();
}

// XSingleServiceFactory
Reference<XInterface > OFactoryProxyHelper::createInstanceWithArguments
(
	const Sequence<Any>& Arguments
)
	throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
{
	return xFactory->createInstanceWithArguments( Arguments );
}

// XServiceInfo
OUString OFactoryProxyHelper::getImplementationName()
	throw(::com::sun::star::uno::RuntimeException)
{
	Reference<XServiceInfo > xInfo( xFactory, UNO_QUERY  );
	if( xInfo.is() )
		return xInfo->getImplementationName();
	return OUString();
}

// XServiceInfo
sal_Bool OFactoryProxyHelper::supportsService(const OUString& ServiceName)
	throw(::com::sun::star::uno::RuntimeException)
{
	Reference<XServiceInfo > xInfo( xFactory, UNO_QUERY  );
	if( xInfo.is() )
		return xInfo->supportsService( ServiceName );
	return sal_False;
}

// XServiceInfo
Sequence< OUString > OFactoryProxyHelper::getSupportedServiceNames(void)
	throw(::com::sun::star::uno::RuntimeException)
{
	Reference<XServiceInfo > xInfo( xFactory, UNO_QUERY  );
	if( xInfo.is() )
		return xInfo->getSupportedServiceNames();
	return Sequence< OUString >();
}

sal_Bool SAL_CALL OFactoryProxyHelper::releaseOnNotification() throw(::com::sun::star::uno::RuntimeException)
{

	Reference<XUnloadingPreference> pref( xFactory, UNO_QUERY);
	if( pref.is())
		return pref->releaseOnNotification();
	return sal_True;
}


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// global function
Reference<XSingleServiceFactory > SAL_CALL createSingleFactory(
	const Reference<XMultiServiceFactory > & rServiceManager,
	const OUString & rImplementationName,
	ComponentInstantiation pCreateFunction,
	const Sequence< OUString > & rServiceNames,
	rtl_ModuleCount *pModCount )
	SAL_THROW( () )
{
	return new OFactoryComponentHelper(
        rServiceManager, rImplementationName, pCreateFunction, 0, &rServiceNames, pModCount, sal_False );
}

// global function
Reference<XSingleServiceFactory > SAL_CALL createFactoryProxy(
	const Reference<XMultiServiceFactory > & rServiceManager,
	const Reference<XSingleServiceFactory > & rFactory )
	SAL_THROW( () )
{
	return new OFactoryProxyHelper(
        rServiceManager, rFactory );
}

// global function
Reference<XSingleServiceFactory > SAL_CALL createOneInstanceFactory(
	const Reference<XMultiServiceFactory > & rServiceManager,
	const OUString & rImplementationName,
	ComponentInstantiation pCreateFunction,
	const Sequence< OUString > & rServiceNames,
	rtl_ModuleCount *pModCount )
	SAL_THROW( () )
{
	return new OFactoryComponentHelper(
        rServiceManager, rImplementationName, pCreateFunction, 0, &rServiceNames, pModCount, sal_True );
//	return new OFactoryUnloadableComponentHelper(
//		rServiceManager, rImplementationName, pCreateFunction, 0, &rServiceNames, pModCount, sal_True );
}

// global function
Reference<XSingleServiceFactory > SAL_CALL createSingleRegistryFactory(
	const Reference<XMultiServiceFactory > & rServiceManager,
	const OUString & rImplementationName,
	const Reference<XRegistryKey > & rImplementationKey )
	SAL_THROW( () )
{
	return new ORegistryFactoryHelper(
        rServiceManager, rImplementationName, rImplementationKey, sal_False );
}

// global function
Reference<XSingleServiceFactory > SAL_CALL createOneInstanceRegistryFactory(
	const Reference<XMultiServiceFactory > & rServiceManager,
	const OUString & rImplementationName,
	const Reference<XRegistryKey > & rImplementationKey )
	SAL_THROW( () )
{
	return new ORegistryFactoryHelper(
        rServiceManager, rImplementationName, rImplementationKey, sal_True );
}

//##################################################################################################
Reference< lang::XSingleComponentFactory > SAL_CALL createSingleComponentFactory(
	ComponentFactoryFunc fptr,
    OUString const & rImplementationName,
    Sequence< OUString > const & rServiceNames,
	rtl_ModuleCount * pModCount)
	SAL_THROW( () )
{
	return new OFactoryComponentHelper(
        Reference< XMultiServiceFactory >(), rImplementationName, 0, fptr, &rServiceNames, pModCount, sal_False );
}

Reference< lang::XSingleComponentFactory > SAL_CALL createOneInstanceComponentFactory(
	ComponentFactoryFunc fptr,
    OUString const & rImplementationName,
    Sequence< OUString > const & rServiceNames,
	rtl_ModuleCount * pModCount)
	SAL_THROW( () )
{
	return new OFactoryComponentHelper(
        Reference< XMultiServiceFactory >(), rImplementationName, 0, fptr, &rServiceNames, pModCount, sal_True );
}

}