diff --git a/CHANGELOG.md b/CHANGELOG.md index 30c8749..c96d5a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [1.8.1] + +### Changed + +- Bug fixes + ## [1.8.0] This release adds support for version 1.8 of the APL specification. diff --git a/aplcore/include/apl/extension/extensionclient.h b/aplcore/include/apl/extension/extensionclient.h index 5c807d7..ec21d0e 100644 --- a/aplcore/include/apl/extension/extensionclient.h +++ b/aplcore/include/apl/extension/extensionclient.h @@ -256,8 +256,7 @@ class ExtensionClient : public Counter, bool mRegistrationProcessed; bool mRegistered; std::string mUri; - RootConfigPtr mRootConfig; - SessionPtr mSession; + std::weak_ptr mRootConfig; std::string mConnectionToken; std::map mLiveData; std::map mActionRefs; diff --git a/aplcore/include/apl/utils/session.h b/aplcore/include/apl/utils/session.h index 6e5cd84..273ad0a 100644 --- a/aplcore/include/apl/utils/session.h +++ b/aplcore/include/apl/utils/session.h @@ -81,6 +81,8 @@ class SessionMessage { SessionMessage(const std::weak_ptr& contextPtr, const char *filename, const char *function); + SessionMessage(const RootConfigPtr& config, const char *filename, const char *function); + ~SessionMessage(); template friend SessionMessage& operator<<(SessionMessage&& sm, T&& value) @@ -130,6 +132,9 @@ class SessionMessage { /// Report content errors using a context object (which contains a session) #define CONSOLE_CTX(CONTEXT) SessionMessage(CONTEXT,__FILENAME__,__func__) +/// Report content errors using a config object pointer (which contains a session) +#define CONSOLE_CFGP(CONFIG_PTR) SessionMessage(CONFIG_PTR,__FILENAME__,__func__) + } // namespace apl #endif // _APL_SESSION_H diff --git a/aplcore/src/component/pagercomponent.cpp b/aplcore/src/component/pagercomponent.cpp index b5aeb89..fae2238 100644 --- a/aplcore/src/component/pagercomponent.cpp +++ b/aplcore/src/component/pagercomponent.cpp @@ -336,7 +336,10 @@ PagerComponent::endPageMove(bool fulfilled, const ActionRef& ref, bool fast) mPageMoveHandler->reset(*this); mPageMoveHandler = nullptr; } - mCurrentAnimation = nullptr; + if (mCurrentAnimation) { + mCurrentAnimation->terminate(); + mCurrentAnimation = nullptr; + } } const ComponentPropDefSet* diff --git a/aplcore/src/engine/rootcontext.cpp b/aplcore/src/engine/rootcontext.cpp index 9a62309..f985ae4 100644 --- a/aplcore/src/engine/rootcontext.cpp +++ b/aplcore/src/engine/rootcontext.cpp @@ -104,12 +104,10 @@ RootContext::RootContext(const Metrics& metrics, const ContentPtr& content, cons RootContext::~RootContext() { assert(mCore); - mCore->sequencer().terminateSequencer(ConfigChangeCommand::SEQUENCER); - mCore->sequencer().terminateSequencer(DisplayStateChangeCommand::SEQUENCER); - clearDirty(); + mCore->terminate(); mCore->dirtyVisualContext.clear(); mTimeManager->terminate(); - mCore->terminate(); + clearDirty(); } void diff --git a/aplcore/src/extension/extensionclient.cpp b/aplcore/src/extension/extensionclient.cpp index 4a05e5d..2f67bcb 100644 --- a/aplcore/src/extension/extensionclient.cpp +++ b/aplcore/src/extension/extensionclient.cpp @@ -43,6 +43,8 @@ id_type ExtensionClient::sCommandIdGenerator = 1000; static const std::string IMPLEMENTED_INTERFACE_VERSION = "1.0"; static const std::string MAX_SUPPORTED_SCHEMA_VERSION = "1.1"; +static const std::string ROOT_CONFIG_MISSING = "RootConfig unavailable. Should not happen."; + static const Bimap sExtensionLiveDataUpdateTypeBimap = { {kExtensionLiveDataUpdateTypeInsert, "Insert"}, {kExtensionLiveDataUpdateTypeUpdate, "Update"}, @@ -85,13 +87,19 @@ ExtensionClient::create(const RootConfigPtr& rootConfig, const std::string& uri) } ExtensionClient::ExtensionClient(const RootConfigPtr& rootConfig, const std::string& uri) - : mRegistrationProcessed(false), mRegistered(false), mUri(uri), mRootConfig(rootConfig), - mSession(rootConfig->getSession()) {} + : mRegistrationProcessed(false), mRegistered(false), mUri(uri), mRootConfig(rootConfig) +{} rapidjson::Value ExtensionClient::createRegistrationRequest(rapidjson::Document::AllocatorType& allocator, Content& content) { + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return rapidjson::Value(rapidjson::kNullType); + } + const auto& settings = content.getExtensionSettings(mUri); - const auto& flags = mRootConfig->getExtensionFlags(mUri); + const auto& flags = rootConfig->getExtensionFlags(mUri); return createRegistrationRequest(allocator, mUri, settings, flags); } @@ -129,21 +137,27 @@ ExtensionClient::getConnectionToken() const bool ExtensionClient::processMessage(const RootContextPtr& rootContext, JsonData&& message) { + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return false; + } + if (!message) { - CONSOLE_S(mSession).log("Malformed offset=%u: %s.", message.offset(), message.error()); + CONSOLE_CFGP(rootConfig).log("Malformed offset=%u: %s.", message.offset(), message.error()); return false; } - const auto& context = rootContext ? rootContext->context() : mRootConfig->evaluationContext(); + const auto& context = rootContext ? rootContext->context() : rootConfig->evaluationContext(); auto evaluated = Object(std::move(message).get()); auto method = propertyAsMapped(context, evaluated, "method", static_cast(-1), sExtensionMethodBimap); if (!mRegistered) { if (mRegistrationProcessed) { - CONSOLE_S(mSession).log("Can't process message after failed registration."); + CONSOLE_CFGP(rootConfig).log("Can't process message after failed registration."); return false; } else if (method != kExtensionMethodRegisterSuccess && method != kExtensionMethodRegisterFailure) { - CONSOLE_S(mSession).log("Can't process message before registration."); + CONSOLE_CFGP(rootConfig).log("Can't process message before registration."); return false; } } @@ -154,7 +168,7 @@ ExtensionClient::processMessage(const RootContextPtr& rootContext, JsonData&& me auto version = propertyAsObject(context, evaluated, "version"); if (version.isNull() || version.getString() != IMPLEMENTED_INTERFACE_VERSION) { - CONSOLE_S(mSession) << "Interface version is wrong. Expected=" << IMPLEMENTED_INTERFACE_VERSION + CONSOLE_CFGP(rootConfig) << "Interface version is wrong. Expected=" << IMPLEMENTED_INTERFACE_VERSION << "; Actual=" << version.toDebugString(); return false; } @@ -184,7 +198,7 @@ ExtensionClient::processMessage(const RootContextPtr& rootContext, JsonData&& me result = processComponentResponse(context, evaluated); break; default: - CONSOLE_S(mSession).log("Unknown method"); + CONSOLE_CFGP(rootConfig).log("Unknown method"); result = false; break; } @@ -195,20 +209,26 @@ ExtensionClient::processMessage(const RootContextPtr& rootContext, JsonData&& me bool ExtensionClient::processRegistrationResponse(const Context& context, const Object& connectionResponse) { + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return false; + } + if (mRegistered) { - CONSOLE_S(mRootConfig->getSession()).log("Can't register extension twice."); + CONSOLE_CFGP(rootConfig).log("Can't register extension twice."); return false; } auto connectionToken = propertyAsObject(context, connectionResponse, "token"); auto schema = propertyAsObject(context, connectionResponse, "schema"); if (connectionToken.isNull() || connectionToken.empty() || schema.isNull()) { - CONSOLE_S(mRootConfig->getSession()).log("Malformed connection response message."); + CONSOLE_CFGP(rootConfig).log("Malformed connection response message."); return false; } if (!readExtension(context, schema)) { - CONSOLE_S(mRootConfig->getSession()).log("Malformed schema."); + CONSOLE_CFGP(rootConfig).log("Malformed schema."); return false; } @@ -223,7 +243,7 @@ ExtensionClient::processRegistrationResponse(const Context& context, const Objec if(environment.isMap()) { // Override environment to one that is provided in response as we set it to nothing when initially register // extension. - mRootConfig->registerExtensionEnvironment(mUri, environment); + rootConfig->registerExtensionEnvironment(mUri, environment); } mRegistered = true; @@ -233,28 +253,34 @@ ExtensionClient::processRegistrationResponse(const Context& context, const Objec bool ExtensionClient::processEvent(const Context& context, const Object& event) { + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return false; + } + auto rootContext = mCachedContext.lock(); if (!rootContext) { - CONSOLE_S(mSession).log("Can't process message without RootContext."); + CONSOLE_CFGP(rootConfig).log("Can't process message without RootContext."); return false; } auto name = propertyAsObject(context, event, "name"); if (!name.isString() || name.empty() || (mEventModes.find(name.getString()) == mEventModes.end())) { - CONSOLE_S(mSession) << "Invalid extension event name for extension=" << mUri + CONSOLE_CFGP(rootConfig) << "Invalid extension event name for extension=" << mUri << " name:" << name.toDebugString(); return false; } auto target = propertyAsObject(context, event, "target"); if (!target.isString() || target.empty() || target.getString() != mUri) { - CONSOLE_S(mSession) << "Invalid extension event target for extension=" << mUri; + CONSOLE_CFGP(rootConfig) << "Invalid extension event target for extension=" << mUri; return false; } auto payload = propertyAsRecursive(context, event, "payload"); if (!payload.isNull() && !payload.isMap()) { - CONSOLE_S(mSession) << "Invalid extension event data for extension=" << mUri; + CONSOLE_CFGP(rootConfig) << "Invalid extension event data for extension=" << mUri; return false; } @@ -270,27 +296,32 @@ ExtensionClient::processEvent(const Context& context, const Object& event) rapidjson::Value ExtensionClient::processCommand(rapidjson::Document::AllocatorType& allocator, const Event& event) { + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return rapidjson::Value(rapidjson::kNullType); + } + if (kEventTypeExtension != event.getType()) { - CONSOLE_S(mSession) << "Invalid extension command type for extension=" << mUri; + CONSOLE_CFGP(rootConfig) << "Invalid extension command type for extension=" << mUri; return rapidjson::Value(rapidjson::kNullType); } auto extensionURI = event.getValue(kEventPropertyExtensionURI); if (!extensionURI.isString() || extensionURI.getString() != mUri) { - CONSOLE_S(mSession) << "Invalid extension command target for extension=" << mUri; + CONSOLE_CFGP(rootConfig) << "Invalid extension command target for extension=" << mUri; return rapidjson::Value(rapidjson::kNullType); } auto commandName = event.getValue(kEventPropertyName); if (!commandName.isString() || commandName.empty()) { - CONSOLE_S(mSession) << "Invalid extension command name for extension=" << mUri - << " command:" << commandName; + CONSOLE_CFGP(rootConfig) << "Invalid extension command name for extension=" << mUri; return rapidjson::Value(rapidjson::kNullType); } auto resourceId = event.getValue(kEventPropertyExtensionResourceId); if (!resourceId.empty() && !resourceId.isString()) { - CONSOLE_S(mSession) << "Invalid extension component handle for extension=" << mUri; + CONSOLE_CFGP(rootConfig) << "Invalid extension component handle for extension=" << mUri; return rapidjson::Value (rapidjson::kNullType); } @@ -325,10 +356,15 @@ ExtensionClient::processCommandResponse(const Context& context, const Object& re { // Resolve any Action associated with a command response. The action is resolved independent // of a Success or Failure in command execution + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return false; + } auto id = propertyAsObject(context, response, "id"); if (!id.isNumber() || id.getInteger() > sCommandIdGenerator) { - CONSOLE_S(mSession) << "Invalid extension command response for extension=" << mUri << " id=" + CONSOLE_CFGP(rootConfig) << "Invalid extension command response for extension=" << mUri << " id=" << id.toDebugString() << " total pending=" << mActionRefs.size(); return false; } @@ -491,21 +527,27 @@ ExtensionClient::reportLiveArrayChanges(const RootContextPtr& rootContext, const bool ExtensionClient::processLiveDataUpdate(const Context& context, const Object& update) { + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return false; + } + auto name = propertyAsObject(context, update, "name"); if (!name.isString() || name.empty() || (mLiveData.find(name.getString()) == mLiveData.end())) { - CONSOLE_S(mSession) << "Invalid LiveData name for extension=" << mUri; + CONSOLE_CFGP(rootConfig) << "Invalid LiveData name for extension=" << mUri; return false; } auto target = propertyAsObject(context, update, "target"); if (!target.isString() || target.empty() || target.getString() != mUri) { - CONSOLE_S(mSession) << "Invalid LiveData target for extension=" << mUri; + CONSOLE_CFGP(rootConfig) << "Invalid LiveData target for extension=" << mUri; return false; } auto operations = propertyAsRecursive(context, update, "operations"); if (!operations.isArray()) { - CONSOLE_S(mSession) << "Invalid LiveData operations for extension=" << mUri; + CONSOLE_CFGP(rootConfig) << "Invalid LiveData operations for extension=" << mUri; return false; } @@ -514,7 +556,7 @@ ExtensionClient::processLiveDataUpdate(const Context& context, const Object& upd auto type = propertyAsMapped(context, operation, "type", static_cast(-1), sExtensionLiveDataUpdateTypeBimap); if (type == static_cast(-1)) { - CONSOLE_S(mSession) << "Wrong operation type for=" << name; + CONSOLE_CFGP(rootConfig) << "Wrong operation type for=" << name; return false; } @@ -528,12 +570,12 @@ ExtensionClient::processLiveDataUpdate(const Context& context, const Object& upd break; default: result = false; - CONSOLE_S(mSession) << "Unknown LiveObject type=" << dataRef.objectType << " for " << dataRef.name; + CONSOLE_CFGP(rootConfig) << "Unknown LiveObject type=" << dataRef.objectType << " for " << dataRef.name; break; } if (!result) { - CONSOLE_S(mSession) << "LiveMap operation failed=" << dataRef.name << " operation=" + CONSOLE_CFGP(rootConfig) << "LiveMap operation failed=" << dataRef.name << " operation=" << sExtensionLiveDataUpdateTypeBimap.at(type); } } @@ -543,10 +585,16 @@ ExtensionClient::processLiveDataUpdate(const Context& context, const Object& upd bool ExtensionClient::updateLiveMap(ExtensionLiveDataUpdateType type, const LiveDataRef& dataRef, const Object& operation) { + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return false; + } + std::string triggerEvent; auto keyObj = operation.opt("key", ""); if (keyObj.empty()) { - CONSOLE_S(mSession) << "Invalid LiveData key for=" << dataRef.name; + CONSOLE_CFGP(rootConfig) << "Invalid LiveData key for=" << dataRef.name; return false; } const auto& key = keyObj.getString(); @@ -564,7 +612,7 @@ ExtensionClient::updateLiveMap(ExtensionLiveDataUpdateType type, const LiveDataR result = liveMap->remove(key); break; default: - CONSOLE_S(mSession) << "Unknown operation for=" << dataRef.name; + CONSOLE_CFGP(rootConfig) << "Unknown operation for=" << dataRef.name; return false; } @@ -574,17 +622,23 @@ ExtensionClient::updateLiveMap(ExtensionLiveDataUpdateType type, const LiveDataR bool ExtensionClient::updateLiveArray(ExtensionLiveDataUpdateType type, const LiveDataRef& dataRef, const Object& operation) { + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return false; + } + std::string triggerEvent; auto item = operation.get("item"); if (item.isNull() && (type != kExtensionLiveDataUpdateTypeRemove && type != kExtensionLiveDataUpdateTypeClear)) { - CONSOLE_S(mSession) << "Malformed items on LiveData update for=" << dataRef.name; + CONSOLE_CFGP(rootConfig) << "Malformed items on LiveData update for=" << dataRef.name; return false; } auto indexObj = operation.opt("index", -1); if (!indexObj.isNumber() && type != kExtensionLiveDataUpdateTypeClear) { - CONSOLE_S(mSession) << "Invalid LiveData index for=" << dataRef.name; + CONSOLE_CFGP(rootConfig) << "Invalid LiveData index for=" << dataRef.name; return false; } auto index = indexObj.getInteger(); @@ -614,7 +668,7 @@ ExtensionClient::updateLiveArray(ExtensionLiveDataUpdateType type, const LiveDat liveArray->clear(); break; default: - CONSOLE_S(mSession) << "Unknown operation for=" << dataRef.name; + CONSOLE_CFGP(rootConfig) << "Unknown operation for=" << dataRef.name; return false; } @@ -624,22 +678,28 @@ ExtensionClient::updateLiveArray(ExtensionLiveDataUpdateType type, const LiveDat bool ExtensionClient::readExtension(const Context& context, const Object& extension) { + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return false; + } + // verify extension schema auto schema = propertyAsString(context, extension, "type"); auto version = propertyAsString(context, extension, "version"); if (schema != "Schema" || version.compare(MAX_SUPPORTED_SCHEMA_VERSION) > 0) { - CONSOLE_S(mSession) << "Unsupported extension schema version:" << version; + CONSOLE_CFGP(rootConfig) << "Unsupported extension schema version:" << version; return false; } // register extension based on URI auto uriObj = propertyAsObject(context, extension, "uri"); if (!uriObj.isString() || uriObj.empty()) { - CONSOLE_S(mSession).log("Missing or invalid extension URI."); + CONSOLE_CFGP(rootConfig).log("Missing or invalid extension URI."); return false; } const auto& uri = uriObj.getString(); - mRootConfig->registerExtension(uri); + rootConfig->registerExtension(uri); mUri = uri; auto types = arrayifyPropertyAsObject(context, extension, "types"); @@ -676,8 +736,14 @@ ExtensionClient::readExtension(const Context& context, const Object& extension) bool ExtensionClient::readExtensionTypes(const Context& context, const Object& types) { + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return false; + } + if (!types.isArray()) { - CONSOLE_S(mSession).log("The extension name=%s has a malformed 'commands' block", mUri.c_str()); + CONSOLE_CFGP(rootConfig).log("The extension name=%s has a malformed 'commands' block", mUri.c_str()); return false; } @@ -685,7 +751,7 @@ ExtensionClient::readExtensionTypes(const Context& context, const Object& types) auto name = propertyAsObject(context, t, "name"); auto props = propertyAsObject(context, t, "properties"); if (!name.isString() || !props.isMap()) { - CONSOLE_S(mSession).log("Invalid extension type for extension=%s", + CONSOLE_CFGP(rootConfig).log("Invalid extension type for extension=%s", mUri.c_str()); continue; } @@ -698,7 +764,7 @@ ExtensionClient::readExtensionTypes(const Context& context, const Object& types) if (extendedType != mTypes.end()) { properties->insert(extendedType->second->begin(), extendedType->second->end()); } else { - CONSOLE_S(mSession) << "Unknown type to extend=" << extended + CONSOLE_CFGP(rootConfig) << "Unknown type to extend=" << extended << " for type=" << name.getString() << " for extension=" << mUri.c_str(); } @@ -715,7 +781,7 @@ ExtensionClient::readExtensionTypes(const Context& context, const Object& types) if (ps.isString()) { ptype = sBindingMap.get(ps.getString(), kBindingTypeAny); } else if (!ps.has("type")) { - CONSOLE_S(mSession).log("Invalid extension property for type=%s extension=%s", + CONSOLE_CFGP(rootConfig).log("Invalid extension property for type=%s extension=%s", name.getString().c_str(), mUri.c_str()); continue; } else { @@ -740,11 +806,17 @@ ExtensionClient::readExtensionTypes(const Context& context, const Object& types) std::vector ExtensionClient::readCommandDefinitionsInternal(const Context& context,const ObjectArray& commands) { std::vector commandDefs; + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return commandDefs; + } + for (const auto& command : commands) { // create a command auto name = propertyAsObject(context, command, "name"); if (!name.isString() || name.empty()) { - CONSOLE_S(mSession).log("Invalid extension command for extension=%s", mUri.c_str()); + CONSOLE_CFGP(rootConfig).log("Invalid extension command for extension=%s", mUri.c_str()); continue; } auto commandName = name.asString(); @@ -768,7 +840,7 @@ ExtensionClient::readCommandDefinitionsInternal(const Context& context,const Obj } if (!mTypes.count(type)) { - CONSOLE_S(mSession).log("The extension name=%s has a malformed `payload` block for command=%s", + CONSOLE_CFGP(rootConfig).log("The extension name=%s has a malformed `payload` block for command=%s", mUri.c_str(), commandName.c_str()); continue; } @@ -781,15 +853,21 @@ ExtensionClient::readCommandDefinitionsInternal(const Context& context,const Obj } // properties // register the command - mRootConfig->registerExtensionCommand(commandDef); + rootConfig->registerExtensionCommand(commandDef); } return commandDefs; } bool ExtensionClient::readExtensionCommandDefinitions(const Context& context, const Object& commands) { + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return false; + } + if (!commands.isArray()) { - CONSOLE_S(mSession).log("The extension name=%s has a malformed 'commands' block", mUri.c_str()); + CONSOLE_CFGP(rootConfig).log("The extension name=%s has a malformed 'commands' block", mUri.c_str()); return false; } readCommandDefinitionsInternal(context, commands.getArray()); @@ -799,8 +877,14 @@ ExtensionClient::readExtensionCommandDefinitions(const Context& context, const O void ExtensionClient::readExtensionComponentCommandDefinitions(const Context& context, const Object& commands, ExtensionComponentDefinition& def) { + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return; + } + if (!commands.isArray()) { - CONSOLE_S(mSession).log("The extension component name=%s has a malformed 'commands' block", mUri.c_str()); + CONSOLE_CFGP(rootConfig).log("The extension component name=%s has a malformed 'commands' block", mUri.c_str()); return; } auto commandDefs = readCommandDefinitionsInternal(context, commands.getArray()); @@ -810,21 +894,27 @@ ExtensionClient::readExtensionComponentCommandDefinitions(const Context& context bool ExtensionClient::readExtensionEventHandlers(const Context& context, const Object& handlers) { + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return false; + } + if (!handlers.isArray()) { - CONSOLE_S(mSession).log("The extension name=%s has a malformed 'events' block", mUri.c_str()); + CONSOLE_CFGP(rootConfig).log("The extension name=%s has a malformed 'events' block", mUri.c_str()); return false; } for (const auto& handler : handlers.getArray()) { auto name = propertyAsObject(context, handler, "name"); if (!name.isString() || name.empty()) { - CONSOLE_S(mSession).log("Invalid extension event handler for extension=%s", mUri.c_str()); + CONSOLE_CFGP(rootConfig).log("Invalid extension event handler for extension=%s", mUri.c_str()); return false; } else { auto mode = propertyAsMapped(context, handler, "mode", kExtensionEventExecutionModeFast, sExtensionEventExecutionModeBimap); mEventModes.emplace(name.asString(), mode); - mRootConfig->registerExtensionEventHandler(ExtensionEventHandler(mUri, name.asString())); + rootConfig->registerExtensionEventHandler(ExtensionEventHandler(mUri, name.asString())); } } @@ -834,21 +924,27 @@ ExtensionClient::readExtensionEventHandlers(const Context& context, const Object bool ExtensionClient::readExtensionLiveData(const Context& context, const Object& liveData) { + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return false; + } + if (!liveData.isArray()) { - CONSOLE_S(mSession).log("The extension name=%s has a malformed 'dataBindings' block", mUri.c_str()); + CONSOLE_CFGP(rootConfig).log("The extension name=%s has a malformed 'dataBindings' block", mUri.c_str()); return false; } for (const auto& binding : liveData.getArray()) { auto name = propertyAsObject(context, binding, "name"); if (!name.isString() || name.empty()) { - CONSOLE_S(mSession).log("Invalid extension data binding for extension=%s", mUri.c_str()); + CONSOLE_CFGP(rootConfig).log("Invalid extension data binding for extension=%s", mUri.c_str()); return false; } auto typeDef = propertyAsObject(context, binding, "type"); if (!typeDef.isString()) { - CONSOLE_S(mSession).log("Invalid extension data binding type for extension=%s", mUri.c_str()); + CONSOLE_CFGP(rootConfig).log("Invalid extension data binding type for extension=%s", mUri.c_str()); return false; } @@ -862,7 +958,7 @@ ExtensionClient::readExtensionLiveData(const Context& context, const Object& liv if (!(mTypes.count(type) // Any LiveData may use defined complex types || (isArray && sBindingMap.has(type)))) { // Arrays also may use primitive types - CONSOLE_S(mSession).log("Data type=%s, for LiveData=%s is invalid", type.c_str(), name.getString().c_str()); + CONSOLE_CFGP(rootConfig).log("Data type=%s, for LiveData=%s is invalid", type.c_str(), name.getString().c_str()); continue; } @@ -912,9 +1008,9 @@ ExtensionClient::readExtensionLiveData(const Context& context, const Object& liv LiveDataRef ldf = {name.getString(), ltype, type, live, addEvent, updateEvent, removeEvent}; mLiveData.emplace(name.getString(), ldf); - mRootConfig->liveData(name.getString(), live); + rootConfig->liveData(name.getString(), live); auto liveObjectWatcher = std::shared_ptr(shared_from_this()); - mRootConfig->liveDataWatcher(name.getString(), liveObjectWatcher); + rootConfig->liveDataWatcher(name.getString(), liveObjectWatcher); } return true; @@ -966,9 +1062,15 @@ ExtensionClient::readExtensionComponentEventHandlers(const Context& context, const Object& handlers, ExtensionComponentDefinition& def) { + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return false; + } + if (!handlers.isNull()) { if (!handlers.isArray()) { - CONSOLE_S(mSession).log("The extension name=%s has a malformed 'events' block", + CONSOLE_CFGP(rootConfig).log("The extension name=%s has a malformed 'events' block", mUri.c_str()); return false; } @@ -976,7 +1078,7 @@ ExtensionClient::readExtensionComponentEventHandlers(const Context& context, for (const auto& handler : handlers.getArray()) { auto name = propertyAsObject(context, handler, "name"); if (!name.isString() || name.empty()) { - CONSOLE_S(mSession).log("Invalid extension event handler for extension=%s", + CONSOLE_CFGP(rootConfig).log("Invalid extension event handler for extension=%s", mUri.c_str()); return false; } @@ -995,15 +1097,21 @@ ExtensionClient::readExtensionComponentEventHandlers(const Context& context, bool ExtensionClient::readExtensionComponentDefinitions(const Context& context, const Object& components) { + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return false; + } + if (!components.isArray()) { - CONSOLE_S(mSession).log("The extension name=%s has a malformed 'components' block", mUri.c_str()); + CONSOLE_CFGP(rootConfig).log("The extension name=%s has a malformed 'components' block", mUri.c_str()); return false; } for (const auto& component : components.getArray()) { auto name = propertyAsObject(context, component, "name"); if (!name.isString() || name.empty()) { - CONSOLE_S(mSession).log("Invalid extension component name for extension=%s", mUri.c_str()); + CONSOLE_CFGP(rootConfig).log("Invalid extension component name for extension=%s", mUri.c_str()); continue; } auto componentName = name.asString(); @@ -1035,7 +1143,7 @@ ExtensionClient::readExtensionComponentDefinitions(const Context& context, const if (ps.isString()) { ptype = sBindingMap.get(ps.getString(), kBindingTypeAny); } else if (!ps.has("type")) { - CONSOLE_S(mSession).log("Invalid extension property extension=%s", mUri.c_str()); + CONSOLE_CFGP(rootConfig).log("Invalid extension property extension=%s", mUri.c_str()); continue; } else { defValue = propertyAsObject(context, ps, "default"); @@ -1056,7 +1164,7 @@ ExtensionClient::readExtensionComponentDefinitions(const Context& context, const componentDef.properties(properties); } - mRootConfig->registerExtensionComponent(componentDef); + rootConfig->registerExtensionComponent(componentDef); } return true; @@ -1065,9 +1173,15 @@ ExtensionClient::readExtensionComponentDefinitions(const Context& context, const rapidjson::Value ExtensionClient::createComponentChange(rapidjson::MemoryPoolAllocator<>& allocator, ExtensionComponent& component) { + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return rapidjson::Value(rapidjson::kNullType); + } + auto extensionURI = component.getUri(); if (extensionURI != mUri) { - CONSOLE_S(mSession) << "Invalid extension command target for extension=" << mUri; + CONSOLE_CFGP(rootConfig) << "Invalid extension command target for extension=" << mUri; return rapidjson::Value(rapidjson::kNullType); } @@ -1122,7 +1236,12 @@ ExtensionClient::processComponentResponse(const Context& context, const Object& // TODO apply component properties } } else { - CONSOLE_S(mSession) << "Unable to find component associated with :" << componentId; + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return false; + } + CONSOLE_CFGP(rootConfig) << "Unable to find component associated with :" << componentId; } return true; } @@ -1130,7 +1249,13 @@ ExtensionClient::processComponentResponse(const Context& context, const Object& bool ExtensionClient::handleDisconnection(const RootContextPtr& rootContext, int errorCode, const std::string& message) { - const auto& context = rootContext ? rootContext->context() : mRootConfig->evaluationContext(); + auto rootConfig = mRootConfig.lock(); + if (!rootConfig) { + LOG(LogLevel::kError) << ROOT_CONFIG_MISSING; + return false; + } + + const auto& context = rootContext ? rootContext->context() : rootConfig->evaluationContext(); if (errorCode != 0) { for (const auto& componentEntry : context.extensionManager().getExtensionComponents()) { diff --git a/aplcore/src/utils/session.cpp b/aplcore/src/utils/session.cpp index 96dc5e5..a7e9f81 100644 --- a/aplcore/src/utils/session.cpp +++ b/aplcore/src/utils/session.cpp @@ -13,6 +13,7 @@ * permissions and limitations under the License. */ +#include "apl/content/rootconfig.h" #include "apl/engine/context.h" #include "apl/utils/session.h" @@ -46,6 +47,12 @@ SessionMessage::SessionMessage(const std::weak_ptr& contextPtr, const c mSession = context->session(); } +SessionMessage::SessionMessage(const RootConfigPtr& config, const char *filename, const char *function) + : mSession(config->getSession()), + mFilename(filename), + mFunction(function), + mUncaught(std::uncaught_exception()) {} + SessionMessage::~SessionMessage() { if (mSession) diff --git a/unit/component/unittest_visual_context.cpp b/unit/component/unittest_visual_context.cpp index 85335ab..f8a2c7a 100644 --- a/unit/component/unittest_visual_context.cpp +++ b/unit/component/unittest_visual_context.cpp @@ -38,11 +38,6 @@ class VisualContextTest : public DocumentWrapper { visualContext = root->serializeVisualContext(vcDoc.GetAllocator()); } - - void TearDown() override { - DocumentWrapper::TearDown(); - } - protected: rapidjson::Document vcDoc; rapidjson::Value visualContext; diff --git a/unit/extension/unittest_extension_mediator.cpp b/unit/extension/unittest_extension_mediator.cpp index bf5f315..ff18383 100644 --- a/unit/extension/unittest_extension_mediator.cpp +++ b/unit/extension/unittest_extension_mediator.cpp @@ -310,13 +310,15 @@ class ExtensionMediatorTest : public DocumentWrapper { extensionProvider = nullptr; mediator = nullptr; testExtensions.clear(); + + DocumentWrapper::TearDown(); } void testLifecycle(); ExtensionRegistrarPtr extensionProvider; // provider instance for tests ExtensionMediatorPtr mediator; - std::map> testExtensions; // direct access to extensions for test + std::map> testExtensions; // direct access to extensions for test }; static const char* EXT_DOC = R"({ @@ -782,7 +784,7 @@ void ExtensionMediatorTest::testLifecycle() { auto ext = extensionProvider->getExtension("aplext:hello:10"); ASSERT_TRUE(ext); // direct access to extension for test inspection - auto hello = testExtensions["aplext:hello:10"]; + auto hello = testExtensions["aplext:hello:10"].lock(); // We have all we need. Inflate. inflate(); @@ -896,7 +898,7 @@ TEST_F(ExtensionMediatorTest, EventBad) { auto ext = extensionProvider->getExtension("aplext:hello:10"); ASSERT_TRUE(ext); // direct access to extension for test inspection - auto hello = testExtensions["aplext:hello:10"]; + auto hello = testExtensions["aplext:hello:10"].lock(); inflate(); @@ -929,7 +931,7 @@ TEST_F(ExtensionMediatorTest, DataUpdateBad) { auto ext = extensionProvider->getExtension("aplext:hello:10"); ASSERT_TRUE(ext); // direct access to extension for test inspection - auto hello = testExtensions["aplext:hello:10"]; + auto hello = testExtensions["aplext:hello:10"].lock(); inflate();