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