@ -1,5 +1,6 @@
# include "serviceregistry.h"
# include "serviceregistry_p.h"
# include "qtmvvmcore_logging_p.h"
# include <QtCore/QGlobalStatic>
# include <QtCore/QRegularExpression>
@ -22,17 +23,29 @@ ServiceRegistry *ServiceRegistry::instance()
void ServiceRegistry : : registerService ( const QByteArray & iid , const QMetaObject * metaObject )
{
QMutexLocker _ ( & d - > serviceMutex ) ;
Q_ASSERT ( ! d - > services . contains ( iid ) ) ; //TODO exception
if ( d - > services . contains ( iid ) )
throw ServiceExistsException ( iid ) ;
d - > services . insert ( iid , QSharedPointer < ServiceRegistryPrivate : : MetaServiceInfo > : : create ( metaObject ) ) ;
}
void ServiceRegistry : : registerService ( const QByteArray & iid , const std : : function < QObject * ( const QObjectList & ) > & fn , QByteArrayList injectables )
{
QMutexLocker _ ( & d - > serviceMutex ) ;
Q_ASSERT ( ! d - > services . contains ( iid ) ) ; //TODO exception
if ( d - > services . contains ( iid ) )
throw ServiceExistsException ( iid ) ;
d - > services . insert ( iid , QSharedPointer < ServiceRegistryPrivate : : FnServiceInfo > : : create ( fn , injectables ) ) ;
}
QObject * ServiceRegistry : : acquireInstanceObject ( const QByteArray & iid )
{
QMutexLocker _ ( & d - > serviceMutex ) ;
auto ref = d - > services . value ( iid ) ;
if ( ref )
return ref - > instance ( d . data ( ) , iid ) ;
else
throw ServiceDependencyException ( iid ) ;
}
// ------------- Private Implementation -------------
ServiceRegistryPrivate : : ServiceRegistryPrivate ( ) :
@ -52,10 +65,16 @@ ServiceRegistryPrivate::ServiceInfo::~ServiceInfo()
QMetaObject : : invokeMethod ( _instance , " deleteLater " ) ;
}
QObject * ServiceRegistryPrivate : : ServiceInfo : : instance ( ServiceRegistryPrivate * d )
QObject * ServiceRegistryPrivate : : ServiceInfo : : instance ( ServiceRegistryPrivate * d , const QByteArray & iid )
{
if ( ! _instance )
if ( ! _instance ) {
logDebug ( ) < < " Constructing service of type " < < iid ;
_instance = construct ( d ) ;
if ( ! _instance )
throw ServiceConstructionException ( " Failed to construct service of type " +
iid +
" with unknown error " ) ;
}
return _instance ;
}
@ -69,8 +88,12 @@ ServiceRegistryPrivate::FnServiceInfo::FnServiceInfo(const std::function<QObject
QObject * ServiceRegistryPrivate : : FnServiceInfo : : construct ( ServiceRegistryPrivate * d ) const
{
QObjectList params ;
foreach ( auto inj , injectables )
params . append ( d - > services . value ( inj ) - > instance ( d ) ) ; //TODO exception
foreach ( auto iid , injectables ) {
auto ref = d - > services . value ( iid ) ;
if ( ! ref )
throw ServiceDependencyException ( iid ) ;
params . append ( ref - > instance ( d , iid ) ) ;
}
return creator ( params ) ;
}
@ -83,26 +106,117 @@ ServiceRegistryPrivate::MetaServiceInfo::MetaServiceInfo(const QMetaObject *meta
QObject * ServiceRegistryPrivate : : MetaServiceInfo : : construct ( ServiceRegistryPrivate * d ) const
{
auto instance = metaObject - > newInstance ( ) ;
Q_ASSERT ( instance ) ; //TODO exception
if ( ! instance ) {
throw ServiceConstructionException ( QByteArrayLiteral ( " Failed to construct object of type " ) +
metaObject - > className ( ) +
QByteArrayLiteral ( " - make shure there is an invokable constructor of the format: Q_INVOKABLE MyClass(QObject*) " ) ) ;
}
static QRegularExpression nameRegex ( QStringLiteral ( R " __(^__qtmvvm_inject_(.+)$)__ " ) ,
QRegularExpression : : OptimizeOnFirstUsageOption ) ;
for ( auto i = 0 ; i < metaObject - > propertyCount ( ) ; i + + ) {
auto prop = metaObject - > property ( i ) ;
auto match = nameRegex . match ( QString : : fromUtf8 ( prop . name ( ) ) ) ;
if ( match . hasMatch ( ) ) {
auto tPropIndex = metaObject - > indexOfProperty ( qUtf8Printable ( match . captured ( 1 ) ) ) ;
if ( tPropIndex = = - 1 )
continue ; //TODO warning
auto tProp = metaObject - > property ( tPropIndex ) ;
auto inject = prop . read ( instance ) . toByteArray ( ) ;
auto injObj = d - > services . value ( inject ) - > instance ( d ) ; //TODO exception
tProp . write ( instance , QVariant : : fromValue ( injObj ) ) ; //TODO check if casting works
try {
for ( auto i = 0 ; i < metaObject - > propertyCount ( ) ; i + + ) {
auto prop = metaObject - > property ( i ) ;
auto match = nameRegex . match ( QString : : fromUtf8 ( prop . name ( ) ) ) ;
if ( match . hasMatch ( ) ) {
auto tPropIndex = metaObject - > indexOfProperty ( qUtf8Printable ( match . captured ( 1 ) ) ) ;
if ( tPropIndex = = - 1 ) {
logWarning ( ) . noquote ( ) < < " Found hint to inject property "
< < match . captured ( 1 )
< < " but no property of that name was found " ;
continue ;
}
auto tProp = metaObject - > property ( tPropIndex ) ;
auto iid = prop . read ( instance ) . toByteArray ( ) ;
auto ref = d - > services . value ( iid ) ;
if ( ! ref )
throw ServiceDependencyException ( iid ) ;
auto injObj = ref - > instance ( d , iid ) ;
tProp . write ( instance , QVariant : : fromValue ( injObj ) ) ; //TODO check if casting works
}
}
auto initMethod = metaObject - > indexOfMethod ( " qtmvvm_init() " ) ;
if ( initMethod ! = - 1 ) {
auto method = metaObject - > method ( initMethod ) ;
method . invoke ( instance ) ;
}
return instance ;
} catch ( . . . ) {
instance - > deleteLater ( ) ;
throw ;
}
}
// ------------- Exceptions Implementation -------------
ServiceExistsException : : ServiceExistsException ( const QByteArray & iid ) :
_msg ( " An interface with the type id \" " + iid + " \" has already been registered " )
{ }
ServiceExistsException : : ServiceExistsException ( const ServiceExistsException * const other ) :
_msg ( other - > _msg )
{ }
const char * ServiceExistsException : : what ( ) const noexcept
{
return _msg . constData ( ) ;
}
void ServiceExistsException : : raise ( ) const
{
throw ( * this ) ;
}
QException * ServiceExistsException : : clone ( ) const
{
return new ServiceExistsException ( this ) ;
}
//TODO call "init" method
return instance ;
ServiceConstructionException : : ServiceConstructionException ( const QByteArray & message ) :
_msg ( message )
{ }
ServiceConstructionException : : ServiceConstructionException ( const ServiceConstructionException * const other ) :
_msg ( other - > _msg )
{ }
const char * ServiceConstructionException : : what ( ) const noexcept
{
return _msg . constData ( ) ;
}
void ServiceConstructionException : : raise ( ) const
{
throw ( * this ) ;
}
QException * ServiceConstructionException : : clone ( ) const
{
return new ServiceConstructionException ( this ) ;
}
ServiceDependencyException : : ServiceDependencyException ( const QByteArray & iid ) :
ServiceConstructionException ( " Failed to construct service because of missing dependency: " + iid )
{ }
ServiceDependencyException : : ServiceDependencyException ( const ServiceDependencyException * const other ) :
ServiceConstructionException ( other )
{ }
void ServiceDependencyException : : raise ( ) const
{
throw ( * this ) ;
}
QException * ServiceDependencyException : : clone ( ) const
{
return new ServiceDependencyException ( this ) ;
}