From 8894fe5880a294481e77278f1af49f3e6af9561c Mon Sep 17 00:00:00 2001 From: matzman Date: Sat, 17 Oct 2015 04:30:26 +0200 Subject: [PATCH] . --- src/hos_cosgi_sitemap/CMakeLists.txt | 6 + src/hos_cosgi_sitemap/examples/test01.json | 35 ++++ .../launch/setup_sitemap.launch | 9 + .../schema/sitemap/sitemap_template.json | 179 ++++++++++++++++++ .../service/sitemap/SitemapServiceImpl.cpp | 58 ++++++ .../service/sitemap/SitemapServiceImpl.h | 10 +- .../sitemap_template/SitemapTemplate.cpp | 60 ++++++ .../sitemap_template/SitemapTemplate.h | 164 ++++++++++++++++ src/hos_launch/launch/hos_master.launch | 1 + 9 files changed, 520 insertions(+), 2 deletions(-) create mode 100644 src/hos_cosgi_sitemap/examples/test01.json create mode 100644 src/hos_cosgi_sitemap/launch/setup_sitemap.launch create mode 100644 src/hos_cosgi_sitemap/schema/sitemap/sitemap_template.json create mode 100644 src/hos_cosgi_sitemap/src/hos/cosgi/service/sitemap/sitemap_template/SitemapTemplate.cpp create mode 100644 src/hos_cosgi_sitemap/src/hos/cosgi/service/sitemap/sitemap_template/SitemapTemplate.h diff --git a/src/hos_cosgi_sitemap/CMakeLists.txt b/src/hos_cosgi_sitemap/CMakeLists.txt index 8f960b4a..99b3722d 100644 --- a/src/hos_cosgi_sitemap/CMakeLists.txt +++ b/src/hos_cosgi_sitemap/CMakeLists.txt @@ -55,6 +55,7 @@ bundle(hos_cosgi_sitemap ${PROJECT_SOURCE_DIR}/src/BundleActivator ${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/sitemap/SitemapServiceImpl ${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/sitemap/webresource/SitemapHandler + ${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/sitemap/sitemap_template/SitemapTemplate ) target_link_libraries(hos_cosgi_sitemap @@ -85,6 +86,11 @@ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc OPTIONAL ) +foreach(dir launch schema examples) + install(DIRECTORY ${dir}/ + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/${dir} + ) +endforeach(dir) ################### diff --git a/src/hos_cosgi_sitemap/examples/test01.json b/src/hos_cosgi_sitemap/examples/test01.json new file mode 100644 index 00000000..9f555be3 --- /dev/null +++ b/src/hos_cosgi_sitemap/examples/test01.json @@ -0,0 +1,35 @@ +{ + "type": "sitemap/sitemap_template", + "title": "TestApp", + "rootpage": { + "type": "sitemap/sitemap_template#/definitions/page", + "title": "Root Page", + "elements": [ + { + "type": "sitemap/sitemap_template#/definitions/text_element", + "label": "Switch0 Text", + "device": { + "id": "dummySwitch0", + "pointer": "" + } + }, { + "type": "sitemap/sitemap_template#/definitions/switch_element", + "label": "Switch0", + "device": { + "id": "dummySwitch0", + "pointer": "" + } + }, { + "type": "sitemap/sitemap_template#/definitions/slider_element", + "label": "Slider0", + "device": { + "id": "dummySlider0", + "pointer": "" + }, + "min": 0, + "max": 1, + "step": 0.1 + } + ] + } +} diff --git a/src/hos_cosgi_sitemap/launch/setup_sitemap.launch b/src/hos_cosgi_sitemap/launch/setup_sitemap.launch new file mode 100644 index 00000000..c96e6881 --- /dev/null +++ b/src/hos_cosgi_sitemap/launch/setup_sitemap.launch @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/hos_cosgi_sitemap/schema/sitemap/sitemap_template.json b/src/hos_cosgi_sitemap/schema/sitemap/sitemap_template.json new file mode 100644 index 00000000..cd93e2f0 --- /dev/null +++ b/src/hos_cosgi_sitemap/schema/sitemap/sitemap_template.json @@ -0,0 +1,179 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Sitemap Template Schema", + "description": "", + "version": "1.0.0", + "type": "object", + "properties": { + "type": { + "type": "string", + "pattern": "sitemap/sitemap_template" + }, + "title": { + "type": "string", + "description": "" + }, + "rootpage": { + "$ref": "#/definitions/page" + } + }, + "additionalProperties": false, + "required": ["title", "rootpage"], + + "definitions": { + + "page": { + "type": "object", + "properties": { + "type": { + "type": "string", + "pattern": "sitemap/sitemap_template#/definitions/page" + }, + "title": { + "type": "string" + }, + "elements": { + "type": "array", + "items": { + "$ref": "#/definitions/element" + } + } + }, + "additionalProperties": false, + "required": ["title", "elements"] + }, + "element": { + "anyOf": [ + { "$ref": "#/definitions/composite_element" }, + { "$ref": "#/definitions/atomic_element" } + ] + }, + "composite_element": { + "anyOf": [ + { "$ref": "#/definitions/frame_element" } + ] + }, + "atomic_element": { + "anyOf": [ + { "$ref": "#/definitions/text_element" }, + { "$ref": "#/definitions/slider_element" }, + { "$ref": "#/definitions/switch_element" } + ] + }, + + "composite_element_base": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "elements": { + "type": "array", + "items": { + "$ref": "#/definitions/element" + } + } + }, + "required": ["elements"] + }, + "frame_element": { + "allOf": [ + { "$ref": "#/definitions/composite_element_base" }, + { + "properties": { + "type": { + "type": "string", + "pattern": "sitemap/sitemap_template#/definitions/frame_element" + } + } + } + ], + "required": ["type"] + }, + + "atomic_element_base": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "format": { + "type": "string" + }, + "device": { + "$ref": "#/definitions/device" + }, + "icon": { + "type": "string" + } + } + }, + "text_element": { + "allOf": [ + { "$ref": "#/definitions/atomic_element_base" }, + { + "properties": { + "type": { + "type": "string", + "pattern": "sitemap/sitemap_template#/definitions/text_element" + } + } + } + ], + "required": ["type"] + }, + "slider_element": { + "allOf": [ + { "$ref": "#/definitions/atomic_element_base" }, + { + "properties": { + "type": { + "type": "string", + "pattern": "sitemap/sitemap_template#/definitions/slider_element" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "step": { + "type": "number" + } + } + } + ], + "required": ["type"] + }, + "switch_element": { + "allOf": [ + { "$ref": "#/definitions/atomic_element_base" }, + { + "properties": { + "type": { + "type": "string", + "pattern": "sitemap/sitemap_template#/definitions/switch_element" + } + } + } + ], + "required": ["type"] + }, + + "device": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "pointer": { + "type": "string" + } + }, + "required": ["id"] + } + } +} \ No newline at end of file diff --git a/src/hos_cosgi_sitemap/src/hos/cosgi/service/sitemap/SitemapServiceImpl.cpp b/src/hos_cosgi_sitemap/src/hos/cosgi/service/sitemap/SitemapServiceImpl.cpp index d36406e2..31eb0fda 100644 --- a/src/hos_cosgi_sitemap/src/hos/cosgi/service/sitemap/SitemapServiceImpl.cpp +++ b/src/hos_cosgi_sitemap/src/hos/cosgi/service/sitemap/SitemapServiceImpl.cpp @@ -19,6 +19,7 @@ namespace cosgi { namespace service { namespace sitemap { +using namespace libvariant; // Service information HOS_SERVICE_IMPL_INFO( SitemapServiceImpl, // Implementation @@ -54,11 +55,68 @@ void SitemapServiceImpl::setRepoService(devicerepository::DeviceRepositoryServic void SitemapServiceImpl::init() noexcept { + // Get public parameters + nodehandle->getParam("sitemap_template_prefix", sitemapTemplatePrefix); + nodehandle->getParam("hos_status_topic", hosStatusTopic); + + // Parse sitemaps + XmlRpc::XmlRpcValue rawValue; + nodehandle->getParam(sitemapTemplatePrefix, rawValue); + if (rawValue.getType() == XmlRpc::XmlRpcValue::TypeStruct) { + for (auto dev : rawValue) { + std::string sitemapName = dev.first; + XmlRpc::XmlRpcValue devRaw = dev.second; + try { + addSitemap(sitemapName, devRaw); + ROS_INFO_STREAM("Created sitemap " << sitemapName << "."); + } catch (std::exception& e) { + ROS_ERROR_STREAM("Could not create sitemap " << sitemapName << ": " << e.what()); + } + } + } + initialized = true; ROS_INFO_STREAM("RuleEngineService: Initialized and Ready."); } +void SitemapServiceImpl::addSitemap(const std::string& name, XmlRpc::XmlRpcValue& rawValue) { + std::lock_guard lock(serviceMutex); + if (rawValue.getType() != XmlRpc::XmlRpcValue::TypeString) { + throw std::runtime_error("sitemap config value is not a string."); + } + std::string strValue = static_cast(rawValue); + libvariant::Variant value = libvariant::DeserializeJSON(strValue); + Variant schema; + try { + schema = coreService->getSchemaLoader().GetSchema("hos:schema://sitemap/sitemap_template"); + } catch(std::exception& e) { + std::stringstream ss; + ss << "Could not load hos:schema://sitemap/sitemap_template: " << e.what(); + throw std::runtime_error(ss.str()); + } + SchemaResult sr = SchemaValidate(schema, value, &coreService->getSchemaLoader()); + if (!sr.Error()) { + auto titleRaw = value["title"]; + if (!titleRaw.IsString()) { + throw std::runtime_error("title is not a string."); + } + std::string title = titleRaw.AsString(); + auto rootpage = value["rootpage"]; + if (!rootpage.IsMap()) { + throw std::runtime_error("rootpage is not a map."); + } + std::shared_ptr st = std::make_shared(title); + st->createPage(rootpage); + sitemapTemplates.insert({name, st}); + } else { + std::stringstream ss; + ss << "Could not validate sitemap config value: " << sr.PrettyPrintMessage(); + throw std::runtime_error(ss.str()); + } +} + + } /* namespace sitemap */ } /* namespace service */ } /* namespace cosgi */ diff --git a/src/hos_cosgi_sitemap/src/hos/cosgi/service/sitemap/SitemapServiceImpl.h b/src/hos_cosgi_sitemap/src/hos/cosgi/service/sitemap/SitemapServiceImpl.h index d9072bb6..1be10418 100644 --- a/src/hos_cosgi_sitemap/src/hos/cosgi/service/sitemap/SitemapServiceImpl.h +++ b/src/hos_cosgi_sitemap/src/hos/cosgi/service/sitemap/SitemapServiceImpl.h @@ -6,8 +6,7 @@ #include #include #include -//#include -// ROS includes +#include "sitemap_template/SitemapTemplate.h" #include // std includes #include @@ -30,9 +29,16 @@ private: devicerepository::DeviceRepositoryService* repoService = nullptr; ros::NodeHandle* nodehandle = nullptr; + std::recursive_mutex serviceMutex; + + std::string sitemapTemplatePrefix = "/hos/sitemap/sitemap_templates"; + std::string hosStatusTopic = "/hos/status/updates"; bool initialized = false; + std::map> sitemapTemplates; + void init() noexcept; + void addSitemap(const std::string& name, XmlRpc::XmlRpcValue& rawValue); public: diff --git a/src/hos_cosgi_sitemap/src/hos/cosgi/service/sitemap/sitemap_template/SitemapTemplate.cpp b/src/hos_cosgi_sitemap/src/hos/cosgi/service/sitemap/sitemap_template/SitemapTemplate.cpp new file mode 100644 index 00000000..f868608d --- /dev/null +++ b/src/hos_cosgi_sitemap/src/hos/cosgi/service/sitemap/sitemap_template/SitemapTemplate.cpp @@ -0,0 +1,60 @@ + +#include "../sitemap_template/SitemapTemplate.h" + +namespace hos { +namespace cosgi { +namespace service { +namespace sitemap { +namespace sitemaptemplate { + + +std::shared_ptr SitemapTemplate::createPage(const libvariant::Variant& param, std::weak_ptr parent) { + std::shared_ptr newPage; + if (parent.expired() && rootPage) { + throw std::runtime_error("There is already a root page."); + } + auto titleRaw = param["title"]; + if (!titleRaw.IsString()) { + throw std::runtime_error("title is not a string."); + } + std::string title = titleRaw.AsString(); + auto elements = param["elements"]; + if (!elements.IsList()) { + throw std::runtime_error("elements is not a list."); + } + newPage = std::make_shared(*this, title, parent); + for ( auto e : elements.AsList()) { + newPage->createElement(e); + } + if (parent.expired()) { + rootPage = newPage; + } + return newPage; +} + + +std::shared_ptr Page::createElement(const libvariant::Variant& param) { + +} + + +std::shared_ptr CompositeElement::createElement(const libvariant::Variant& param) { + +} + + +std::shared_ptr AtomicElement::createLinkedToPage(const libvariant::Variant& param) { + +} + + +std::shared_ptr AtomicElement::createDevice(const libvariant::Variant& param) { + +} + + +} // namespace sitemaptemplate +} // namespace sitemap +} // namespace service +} // namespace cosgi +} // namespace hos diff --git a/src/hos_cosgi_sitemap/src/hos/cosgi/service/sitemap/sitemap_template/SitemapTemplate.h b/src/hos_cosgi_sitemap/src/hos/cosgi/service/sitemap/sitemap_template/SitemapTemplate.h new file mode 100644 index 00000000..1e502cb7 --- /dev/null +++ b/src/hos_cosgi_sitemap/src/hos/cosgi/service/sitemap/sitemap_template/SitemapTemplate.h @@ -0,0 +1,164 @@ + +#pragma once + +// hos includes +#include +// libvariant +#include +// std includes +#include +#include +#include +#include +#include + + +namespace hos { +namespace cosgi { +namespace service { +namespace sitemap { +namespace sitemaptemplate { + + +class Page; +class Element; +class AtomicElement; +class CompositeElement; +class Device; + + + +class SitemapTemplate { +private: + std::string title; + std::shared_ptr rootPage; + +public: + SitemapTemplate(const std::string& title) : title(title) {} + + std::shared_ptr createPage(const libvariant::Variant& param, std::weak_ptr parent = std::weak_ptr()); + + std::shared_ptr getRootPage() noexcept { return rootPage; }; +}; + + + +class Page { +private: + SitemapTemplate& sitemap; + std::weak_ptr parent; + std::string title; + std::vector> elements; + +public: + Page(SitemapTemplate& sitemap, const std::string& title, std::weak_ptr parent = std::weak_ptr()) + : sitemap(sitemap), title(title) {} + + SitemapTemplate& getSiteMap() noexcept { return sitemap; } + std::shared_ptr getParent() noexcept { return parent.lock(); } + + std::shared_ptr createElement(const libvariant::Variant& param); + const std::vector>& getElements() noexcept { return elements; } +}; + + +enum class ElementType { + // composite elements + Frame, + + // atomic elements + Text, + Switch, + Slider +}; + +class Element { +private: + static std::atomic nextID; + + uint64_t id; + bool compositeFlag; + ElementType type; + Page& page; + std::weak_ptr parent; + + std::string label; + std::string icon; + +public: + Element( Page& page, + bool isComposite, + ElementType type, + std::weak_ptr parent, + const std::string& label, + const std::string& icon ) + : id(nextID.fetch_add(1)), compositeFlag(isComposite), type(type), page(page), parent(parent), label(label), icon(icon) {} + virtual ~Element() {} + + uint64_t getID() noexcept { return id; } + const std::string& getLabel() noexcept { return label; } + const std::string& getIcon() noexcept { return icon; } + + Page& getPage() noexcept { return page; } + std::shared_ptr getParent() noexcept { return parent.lock(); } + + bool isComposite() noexcept { return compositeFlag; }; + ElementType getType() noexcept { return type; } +}; + + + +class CompositeElement : public Element { +private: + std::vector> elements; + +public: + CompositeElement(Page& page, ElementType etype, const std::string& label, const std::string& icon, + std::weak_ptr parent = std::weak_ptr()) + : Element(page, true, etype, parent, label, icon) {} + + std::shared_ptr createElement(const libvariant::Variant& param); + const std::vector>& getElements() noexcept { return elements; } +}; + + + +class AtomicElement : public Element { +private: + std::string format; + std::shared_ptr device; + libvariant::Variant additionalParams; + std::shared_ptr linkedToPage; + +public: + AtomicElement(Page& page, ElementType etype, const std::string& label, const std::string& icon, + const std::string& format, std::shared_ptr device, libvariant::Variant additionalParams, + std::weak_ptr parent = std::weak_ptr()) + : Element(page, false, etype, parent, label, icon), format(format), device(device), additionalParams(additionalParams) {} + + const std::string& getFormat() { return format; } + std::shared_ptr createDevice(const libvariant::Variant& param); + std::shared_ptr getDevice() { return device; } + const libvariant::Variant& getAdditionalParams() { return additionalParams; } + + std::shared_ptr createLinkedToPage(const libvariant::Variant& param); + std::shared_ptr getLinkedToPage() { return linkedToPage; } +}; + + + +class Device { +private: + +public: + +}; + + + +} // namespace sitemaptemplate +} // namespace sitemap +} // namespace service +} // namespace cosgi +} // namespace hos + diff --git a/src/hos_launch/launch/hos_master.launch b/src/hos_launch/launch/hos_master.launch index 0b72f4c3..dc225a3c 100644 --- a/src/hos_launch/launch/hos_master.launch +++ b/src/hos_launch/launch/hos_master.launch @@ -1,4 +1,5 @@ + \ No newline at end of file