diff --git a/BlueBerry/Bundles/org.blueberry.osgi/files.cmake b/BlueBerry/Bundles/org.blueberry.osgi/files.cmake index 99ffda3099..aac201affe 100644 --- a/BlueBerry/Bundles/org.blueberry.osgi/files.cmake +++ b/BlueBerry/Bundles/org.blueberry.osgi/files.cmake @@ -1,77 +1,78 @@ # Files which should be processed by Qts moc SET(MOC_H_FILES src/internal/berryCTKPluginActivator.h src/internal/berryExtensionPointService.h ) SET(CACHED_RESOURCE_FILES plugin.xml ) SET(EVENT_CPP_FILES berryBundleEvent.cpp berryPlatformEvent.cpp ) SET(INTERNAL_CPP_FILES berryBundle.cpp berryBundleContext.cpp berryBundleDirectory.cpp berryBundleManifest.cpp berryCodeCache.cpp berryCTKPluginActivator.cpp berryDefaultActivator.cpp berryConfigurationElement.cpp berryExtension.cpp berryExtensionPoint.cpp berryExtensionPointService.cpp berryInternalPlatform.cpp berryPlatformLogChannel.cpp berryProvisioningInfo.cpp berrySystemBundle.cpp berrySystemBundleActivator.cpp berrySystemBundleManifest.cpp ) SET(SERVICE_CPP_FILES berryIExtensionPointService.cpp berryService.cpp berryServiceRegistry.cpp ) SET(SRC_CPP_FILES berryDebugBreakpointManager.cpp berryException.cpp + berryExtensionType.cpp berryIBundleManifest.cpp berryIDebugObjectListener.cpp berryBundleLoader.cpp berryDebugUtil.cpp berryObject.cpp berryObjects.cpp berryPlatform.cpp berryPlatformException.cpp berryPlugin.cpp berryStackTrace.cpp # application application/berryIApplication.cpp application/berryStarter.cpp ) SET(CPP_FILES manifest.cpp) foreach(file ${SRC_CPP_FILES}) SET(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${EVENT_CPP_FILES}) SET(CPP_FILES ${CPP_FILES} src/event/${file}) endforeach(file ${EVENT_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) SET(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) foreach(file ${SERVICE_CPP_FILES}) SET(CPP_FILES ${CPP_FILES} src/service/${file}) endforeach(file ${SERVICE_CPP_FILES}) diff --git a/BlueBerry/Bundles/org.blueberry.osgi/src/berryExtensionType.cpp b/BlueBerry/Bundles/org.blueberry.osgi/src/berryExtensionType.cpp new file mode 100644 index 0000000000..0f0f65b0e5 --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.osgi/src/berryExtensionType.cpp @@ -0,0 +1,202 @@ +/*========================================================================= + + Program: BlueBerry Platform + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) German Cancer Research Center, Division of Medical and + Biological Informatics. All rights reserved. + See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "berryExtensionType.h" + +#include +#include + +#include + +namespace berry { + +class CustomTypeInfo +{ +public: + CustomTypeInfo() : typeName(), constr(0), destr(0) + {} + + QByteArray typeName; + ExtensionType::Constructor constr; + ExtensionType::Destructor destr; + + int alias; +}; + +//Q_DECLARE_TYPEINFO(QCustomTypeInfo, Q_MOVABLE_TYPE); +Q_GLOBAL_STATIC(QVector, customTypes) +Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock) + +const char* ExtensionType::typeName(int type) +{ + + const QVector* const ct = customTypes(); + QReadLocker locker(customTypesLock()); + return ct && ct->count() > type && !ct->at(type).typeName.isEmpty() + ? ct->at(type).typeName.constData() + : static_cast(0); +} + + +/*! \internal + Similar to ExtensionType::type(), but doesn't lock the mutex. +*/ +static int extensionTypeCustomType_unlocked(const char *typeName, int length) +{ + const QVector* const ct = customTypes(); + if (!ct) return 0; + + for (int v = 0; v < ct->count(); ++v) + { + const CustomTypeInfo& customInfo = ct->at(v); + if ((length == customInfo.typeName.size()) + && !std::strcmp(typeName, customInfo.typeName.constData())) + { + if (customInfo.alias >= 0) + return customInfo.alias; + return v; + } + } + return 0; +} + +int ExtensionType::registerType(const char *typeName, Destructor destructor, + Constructor constructor) +{ + QVector* ct = customTypes(); + if (!ct || !typeName || !destructor || !constructor) + return -1; + + QByteArray normalizedTypeName = QMetaObject::normalizedType(typeName); + + QWriteLocker locker(customTypesLock()); + int idx = extensionTypeCustomType_unlocked(normalizedTypeName.constData(), + normalizedTypeName.size()); + if (!idx) + { + CustomTypeInfo inf; + inf.typeName = normalizedTypeName; + inf.constr = constructor; + inf.destr = destructor; + inf.alias = -1; + idx = ct->size(); + ct->append(inf); + } + + return idx; +} + +int ExtensionType::registerTypedef(const char* typeName, int aliasId) +{ + QVector* ct = customTypes(); + if (!ct || !typeName) return -1; + + QByteArray normalizedTypeName = QMetaObject::normalizedType(typeName); + + QWriteLocker locker(customTypesLock()); + int idx = extensionTypeCustomType_unlocked(normalizedTypeName.constData(), + normalizedTypeName.size()); + + if (idx) return idx; + + CustomTypeInfo inf; + inf.typeName = normalizedTypeName; + inf.alias = aliasId; + inf.constr = 0; + inf.destr = 0; + ct->append(inf); + return aliasId; +} + +void ExtensionType::unregisterType(const char* typeName) +{ + QVector *ct = customTypes(); + if (!ct || !typeName) return; + + QByteArray normalizedTypeName = QMetaObject::normalizedType(typeName); + + QWriteLocker locker(customTypesLock()); + for (int v = 0; v < ct->count(); ++v) + { + if (ct->at(v).typeName == typeName) + { + CustomTypeInfo &inf = (*ct)[v]; + inf.typeName.clear(); + inf.constr = 0; + inf.destr = 0; + inf.alias = -1; + } + } +} + +bool ExtensionType::isRegistered(int type) +{ + QReadLocker locker(customTypesLock()); + const QVector* const ct = customTypes(); + return ((ct && ct->count() > type) && + !ct->at(type).typeName.isEmpty()); +} + +int ExtensionType::type(const char *typeName) +{ + int length = std::strlen(typeName); + if (!length) return 0; + + QReadLocker locker(customTypesLock()); + int type = extensionTypeCustomType_unlocked(typeName, length); + if (!type) + { + const QByteArray normalizedTypeName = QMetaObject::normalizedType(typeName); + type = extensionTypeCustomType_unlocked(normalizedTypeName.constData(), + normalizedTypeName.size()); + } + + return type; +} + +QObject* ExtensionType::construct(int type) +{ + const QVector * const ct = customTypes(); + + Constructor constr = 0; + + QReadLocker locker(customTypesLock()); + if (!ct || ct->count() <= type) + return 0; + if (ct->at(type).typeName.isEmpty()) + return 0; + constr = ct->at(type).constr; + return constr(); +} + +void ExtensionType::destroy(int type, QObject* data) +{ + if (!data) return; + + const QVector * const ct = customTypes(); + if (!ct) return; + + Destructor destr = 0; + + QReadLocker locker(customTypesLock()); + if (ct->at(type).typeName.isEmpty()) + return; + destr = ct->at(type).destr; + destr(data); +} + +} // end namespace berry diff --git a/BlueBerry/Bundles/org.blueberry.osgi/src/berryExtensionType.h b/BlueBerry/Bundles/org.blueberry.osgi/src/berryExtensionType.h new file mode 100644 index 0000000000..cfc89212bc --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.osgi/src/berryExtensionType.h @@ -0,0 +1,193 @@ +/*========================================================================= + + Program: BlueBerry Platform + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) German Cancer Research Center, Division of Medical and + Biological Informatics. All rights reserved. + See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#ifndef BERRY_EXTENSION_TYPES_H +#define BERRY_EXTENSION_TYPES_H + +#include + +#include + +namespace berry { + +/** + * \brief The ExtensionType class manages named types + * \threadsafe + * + * The class associates a type + * name to a type so that it can be created and destructed + * dynamically at run-time. Call registerExtensionType() to make + * the type known. + * + * Any class or struct that inherits from QObject and has a public + * default constructor, and a public destructor can be registered. + * + */ +class BERRY_OSGI ExtensionType +{ + +public: + + typedef void (*Destructor)(QObject *); + typedef QObject* (*Constructor)(); + + /** + * \internal + * + * Registers a type with typeName, a destructor, and a constructor. + * Returns the type's handle, or -1 if the type could not be registered. + */ + static int registerType(const char* typeName, Destructor destructor, + Constructor constructor); + + /** + * \internal + * + * Registers a type as an alias of another type (typedef) + */ + static int registerTypedef(const char* typeName, int aliasId); + + /** + * Unregisters a type with typeName. + * + * \sa type() + * \sa typeName() + */ + static void unregisterType(const char* typeName); + + /** + * Returns a handle to the type called typeName, or 0 if there is + * no such type. + * + * \sa isRegistered() + * \sa typeName() + */ + static int type(const char* typeName); + + /** + * Returns the type name associated with the given type, or 0 if no + * matching type was found. The returned pointer must not be deleted. + * + * \sa type() + * \sa isRegistered() + */ + static const char* typeName(int type); + + /** + * Returns true if the datatype with ID type is registered; + * otherwise returns false. + * + * \sa type() + * \sa typeName() + */ + static bool isRegistered(int type); + + /** + * Creates a default type. + * + * \sa destroy() + * \sa isRegistered() + */ + static QObject* construct(int type); + + /** + * Destroys the data, assuming it is of the type given. + * + * \sa construct() + * \sa isRegistered() + */ + static void destroy(int type, QObject* data); +}; + +template +void extensionTypeDeleteHelper(T* t) +{ + delete t; +} + +template +QObject* extensionTypeConstructHelper(const T* t) +{ + return new T; +} + +template +struct ExtensionTypeId +{ + enum { Defined = 0 }; +}; + +template +struct ExtensionTypeId2 +{ + enum { Defined = ExtensionTypeId::Defined }; + static inline int extensiontype_id() { return ExtensionTypeId::extensiontype_id(); } +}; + +namespace internal { + +template ::Defined> +struct ExtensionTypeIdHelper +{ + static inline int extensiontype_id() + { return ExtensionTypeId2::extensiontype_id(); } +}; + +template +struct ExtensionTypeIdHelper +{ + static inline int extensiontype_id() + { return -1; } +}; + +} // end namespace internal + +/** + * \threadsafe + * + * Registers the type name typeName for the type T. Returns + * the internal ID used by ExtensionType. Any class or struct that has a + * public default constructor, a public destructor, and a QObject base + * class can be registered. + * + * After a type has been registered, you can create and destroy + * objects of that type dynamically at run-time. + */ +template +int registerExtensionType(const char* typeName +#ifndef DOXYGEN_SKIP + , T* dummy = 0 +#endif +) +{ + const int typedefOf = dummy ? -1 : internal::ExtensionTypeIdHelper::extensiontype_id(); + if (typedefOf != -1) + return ExtensionType::registerTypedef(typeName, typedefOf); + + typedef QObject*(*ConstructPtr)(const T*); + ConstructPtr cptr = extensionTypeConstructHelper; + typedef void(*DeletePtr)(T*); + DeletePtr dptr = extensionTypeDeleteHelper; + + return ExtensionType::registerType(typeName, reinterpret_cast(dptr), + reinterpret_cast(cptr)); +} + +} // end namespace berry + + +#endif // BERRY_EXTENSION_TYPES_H diff --git a/BlueBerry/Bundles/org.blueberry.osgi/src/berryMacros.h b/BlueBerry/Bundles/org.blueberry.osgi/src/berryMacros.h index 932bc53afa..266f0b6c74 100644 --- a/BlueBerry/Bundles/org.blueberry.osgi/src/berryMacros.h +++ b/BlueBerry/Bundles/org.blueberry.osgi/src/berryMacros.h @@ -1,117 +1,120 @@ /*========================================================================= Program: BlueBerry Platform Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef __BERRY_MACROS_H__ #define __BERRY_MACROS_H__ #include "berryWeakPointer.h" +#include "berryExtensionType.h" + #define berryNameMacro(className) \ virtual const char* GetClassName() const \ { return #className; }\ static const char* GetStaticClassName() \ { return #className; }\ #define berryManifestMacro(className, namespaze) \ static const char* GetManifestName() \ { return #namespaze #className; } \ #define berryObjectMacro(className) \ typedef className Self; \ typedef berry::SmartPointer Pointer; \ typedef berry::SmartPointer ConstPointer; \ typedef berry::WeakPointer WeakPtr; \ typedef berry::WeakPointer ConstWeakPtr; \ berryNameMacro(className) \ #define berryInterfaceMacro(className, namespaze) \ public: \ berryObjectMacro(className) \ berryManifestMacro(className, namespaze) \ #define berrySimpleInterfaceMacro(className, namespaze) \ protected: className() {} \ public: \ berryNameMacro(className) \ berryManifestMacro(className, namespaze) \ #define berryNewMacro(x) \ static Pointer New(void) \ { \ Pointer smartPtr(new x); \ return smartPtr; \ } \ #define berryNewMacro1Param(x, type1) \ static Pointer New(type1 param1) \ { \ Pointer smartPtr(new x(param1)); \ return smartPtr; \ } \ #define berryNewMacro2Param(x, type1, type2) \ static Pointer New(type1 param1, type2 param2) \ { \ Pointer smartPtr(new x(param1, param2)); \ return smartPtr; \ } \ #define berryNewMacro3Param(x, type1, type2, type3) \ static Pointer New(type1 param1, type2 param2, type3 param3) \ { \ Pointer smartPtr (new x(param1, param2, param3)); \ return smartPtr; \ } \ #ifndef BERRY_NO_TYPESAFE_FLAGS #include "berryFlags.h" #define BERRY_DECLARE_FLAGS(_Flags, _Enum)\ typedef berry::Flags<_Enum> _Flags; #if defined _MSC_VER && _MSC_VER < 1300 # define BERRY_DECLARE_INCOMPATIBLE_FLAGS(_Flags) #else # define BERRY_DECLARE_INCOMPATIBLE_FLAGS(_Flags) \ inline berry::IncompatibleFlag operator|(_Flags::enum_type f1, int f2) \ { return berry::IncompatibleFlag(int(f1) | f2); } #endif #define BERRY_DECLARE_OPERATORS_FOR_FLAGS(_Flags) \ inline berry::Flags<_Flags::enum_type> operator|(_Flags::enum_type f1, _Flags::enum_type f2) \ { return berry::Flags<_Flags::enum_type>(f1) | f2; } \ inline berry::Flags<_Flags::enum_type> operator|(_Flags::enum_type f1, berry::Flags<_Flags::enum_type> f2) \ { return f2 | f1; } BERRY_DECLARE_INCOMPATIBLE_FLAGS(_Flags) #else /* BERRY_NO_TYPESAFE_FLAGS */ #define BERRY_DECLARE_FLAGS(_Flags, _Enum)\ typedef uint _Flags; #define BERRY_DECLARE_OPERATORS_FOR_FLAGS(_Flags) #endif /* BERRY_NO_TYPESAFE_FLAGS */ + #define BERRY_REGISTER_EXTENSION_CLASS(_ClassType, _PluginContext)\ {\ QString typeName = _PluginContext->getPlugin()->getSymbolicName();\ typeName = (typeName + "_") + _ClassType::staticMetaObject.className();\ - qRegisterMetaType<_ClassType>(typeName.toAscii().data());\ + ::berry::registerExtensionType<_ClassType>(typeName.toAscii().data());\ } #endif /*__BERRY_MACROS_H__*/ diff --git a/BlueBerry/Bundles/org.blueberry.osgi/src/service/berryIConfigurationElement.h b/BlueBerry/Bundles/org.blueberry.osgi/src/service/berryIConfigurationElement.h index 654e385b48..c4efee5222 100644 --- a/BlueBerry/Bundles/org.blueberry.osgi/src/service/berryIConfigurationElement.h +++ b/BlueBerry/Bundles/org.blueberry.osgi/src/service/berryIConfigurationElement.h @@ -1,156 +1,157 @@ /*========================================================================= Program: BlueBerry Platform Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef BERRYIEXTENSIONELEMENT_H_ #define BERRYIEXTENSIONELEMENT_H_ #include "berryLog.h" #include #include "../berryBundleLoader.h" #include "../berryPlatformException.h" +#include "berryExtensionType.h" #include "berryIExecutableExtension.h" #include "berryIExtension.h" #include #include namespace berry { struct IExtension; struct BERRY_OSGI IConfigurationElement : public Object { berryObjectMacro(IConfigurationElement); public: typedef std::vector vector; template C* CreateExecutableExtension(const std::string& propertyName, const std::string& manifestName) { std::string className; if (this->GetAttribute(propertyName, className)) { try { C* cl = m_ClassLoader->LoadClass(m_Contributor, className, manifestName); // check if we have extension adapter and initialize if (dynamic_cast(cl) != 0) { // make the call even if the initialization string is null dynamic_cast(cl)->SetInitializationData(Pointer(this), propertyName, Object::Pointer(0)); } if (cl == 0) { BERRY_WARN << "Could not load executable extension " << className << " from " << GetContributor(); } return cl; } catch (Poco::Exception& e) { BERRY_ERROR << "Error loading class: " << e.displayText() << std::endl; throw e; } } throw CoreException("Missing attribute", propertyName); } template C* CreateExecutableExtension(const std::string& propertyName) { std::string className; if (this->GetAttribute(propertyName, className)) { std::string contributor = this->GetContributor(); QSharedPointer plugin = Platform::GetCTKPlugin(QString::fromStdString(contributor)); if (!plugin.isNull()) { // immediately start the plugin but do not change the plugins autostart setting plugin->start(ctkPlugin::START_TRANSIENT); QString typeName = plugin->getSymbolicName() + "_" + QString::fromStdString(className); - int metaTypeId = QMetaType::type(typeName.toAscii().data()); - if (metaTypeId == 0) + int extensionTypeId = ExtensionType::type(typeName.toAscii().data()); + if (extensionTypeId == 0) { - BERRY_WARN << "The class " << className << " was not registered as a Qt MetaType using BERRY_REGISTER_EXTENSION_CLASS(type, pluginContext) or you forgot to run Qt's moc on the header file. " + BERRY_WARN << "The class " << className << " was not registered as an Extension Type using BERRY_REGISTER_EXTENSION_CLASS(type, pluginContext) or you forgot to run Qt's moc on the header file. " "Legacy BlueBerry bundles should use CreateExecutableExtension(propertyName, C::GetManifestName()) instead."; } else { - QObject* obj = static_cast(QMetaType::construct(metaTypeId)); + QObject* obj = ExtensionType::construct(extensionTypeId); // check if we have extension adapter and initialize if (IExecutableExtension* execExt = qobject_cast(obj)) { // make the call even if the initialization string is null execExt->SetInitializationData(Pointer(this), propertyName, Object::Pointer(0)); } C* interface = qobject_cast(obj); if (interface == 0) { BERRY_WARN << "The QObject subclass " << className << " does not seem to implement the required interface class, or you forgot the Q_INTERFACES macro."; } return interface; } } else { BERRY_WARN << "Trying to create an executable extension (from " << this->GetDeclaringExtension()->GetExtensionPointIdentifier() << " in " << contributor << ") from a non-CTK plug-in. " "Use the CreateExecutableExtension(propertyName, manifestName) method instead."; } } return 0; } virtual bool GetAttribute(const std::string& name, std::string& value) const = 0; virtual bool GetBoolAttribute(const std::string& name, bool& value) const = 0; virtual const std::vector GetChildren() const = 0; virtual const std::vector GetChildren(const std::string& name) const = 0; virtual std::string GetValue() const = 0; virtual std::string GetName() const = 0; virtual const IConfigurationElement* GetParent() const = 0; virtual const std::string& GetContributor() const = 0; virtual const IExtension* GetDeclaringExtension() const = 0; virtual ~IConfigurationElement() {}; protected: BundleLoader* m_ClassLoader; std::string m_Contributor; }; } // namespace berry #endif /*BERRYIEXTENSIONELEMENT_H_*/