.
This commit is contained in:
@@ -9,4 +9,9 @@
|
||||
extern "C" {
|
||||
#include "celix/framework.h"
|
||||
#include "celix/linked_list_iterator.h"
|
||||
#include "celix/bundle_activator.h"
|
||||
#include "celix/bundle_context.h"
|
||||
#include "celix/service_listener.h"
|
||||
#include "celix/service_reference.h"
|
||||
#include "celix/constants.h"
|
||||
}
|
||||
|
||||
@@ -22,6 +22,11 @@ namespace core {
|
||||
|
||||
|
||||
|
||||
enum class CoreServiceEventType : int {
|
||||
STARTUP_FINISHED = 1,
|
||||
SHUTDOWN = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for events emitted by the CoreService.
|
||||
*/
|
||||
@@ -29,12 +34,10 @@ class CoreServiceEvent {
|
||||
public:
|
||||
typedef std::chrono::system_clock::time_point timestamp_t;
|
||||
|
||||
enum class EventType : int { STARTUP_FINISHED = 1, SHUTDOWN = 2 };
|
||||
|
||||
const EventType eventType;
|
||||
CoreServiceEventType eventType;
|
||||
const timestamp_t timestamp;
|
||||
|
||||
CoreServiceEvent(EventType type, const timestamp_t timestamp = std::chrono::system_clock::now())
|
||||
CoreServiceEvent(CoreServiceEventType type, const timestamp_t timestamp = std::chrono::system_clock::now())
|
||||
: eventType(type), timestamp(timestamp) {}
|
||||
};
|
||||
|
||||
@@ -48,7 +51,7 @@ public:
|
||||
class StartupFinishedEvent
|
||||
: public CoreServiceEvent {
|
||||
public:
|
||||
StartupFinishedEvent() : CoreServiceEvent(EventType::STARTUP_FINISHED) {}
|
||||
StartupFinishedEvent() : CoreServiceEvent(CoreServiceEventType::STARTUP_FINISHED) {}
|
||||
};
|
||||
|
||||
|
||||
@@ -61,7 +64,7 @@ public:
|
||||
class ShutdownEvent
|
||||
: public CoreServiceEvent {
|
||||
public:
|
||||
ShutdownEvent() : CoreServiceEvent(EventType::SHUTDOWN) {}
|
||||
ShutdownEvent() : CoreServiceEvent(CoreServiceEventType::SHUTDOWN) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -22,7 +22,9 @@ template<> const int implementation::ServiceInfo<CoreServiceImpl>::minor = 0;
|
||||
|
||||
|
||||
CoreServiceImpl::CoreServiceImpl(ros::NodeHandle& publicNodeHandle, ros::NodeHandle& privateNodeHandle)
|
||||
: publicNodeHandle(publicNodeHandle), privateNodeHandle(privateNodeHandle) {}
|
||||
: publicNodeHandle(publicNodeHandle), privateNodeHandle(privateNodeHandle) {
|
||||
schemaLoader.reset(new utils::SchemaLoader());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -33,43 +33,20 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
CoreServiceImpl(ros::NodeHandle& publicNodeHandle, ros::NodeHandle& privateNodeHandle);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
////////////// Public Service Implementations //////////////
|
||||
////////////////////////////////////////////////////////////
|
||||
/* Public Service Implementations */
|
||||
|
||||
/**
|
||||
* Returns a reference to a node handle with public namespace.
|
||||
*
|
||||
* \return public node handle
|
||||
*/
|
||||
virtual ros::NodeHandle& getPublicNodeHandle() override {
|
||||
return publicNodeHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to a node handle with private namespace.
|
||||
*
|
||||
* \return private node handle
|
||||
*/
|
||||
virtual ros::NodeHandle& getPrivateNodeHandle() override {
|
||||
return privateNodeHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request an application shutdown
|
||||
*/
|
||||
virtual void requestShutdown() override;
|
||||
|
||||
/**
|
||||
* Returns a reference to the schema loader.
|
||||
*
|
||||
* \return schema loader.
|
||||
*/
|
||||
virtual utils::SchemaLoader& getSchemaLoader() override {
|
||||
return *schemaLoader;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
// Boost
|
||||
#include <boost/format.hpp>
|
||||
// ROS
|
||||
#include "ros/ros.h"
|
||||
#include <ros/ros.h>
|
||||
// APR
|
||||
#include <apr_general.h>
|
||||
#include <apr_strings.h>
|
||||
|
||||
+121
-25
@@ -1,5 +1,6 @@
|
||||
#ifndef _HOS_DEVICEREPOSITORY_SERVICE_H_
|
||||
#define _HOS_DEVICEREPOSITORY_SERVICE_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
#include <hos/cosgi/service/Interface.h>
|
||||
@@ -26,6 +27,22 @@ using namespace libvariant;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Device event type.
|
||||
*
|
||||
* DeviceRepositoryService emits DEVICE_ADDED, DEVICE_REMOVED.
|
||||
* Device emits STATUS_UPDATE_RECEIVED, COMMAND_RECEIVED, STATE_CHANGED, DEVICE_REMOVED.
|
||||
**/
|
||||
enum class DeviceEventType : int {
|
||||
DEVICE_ADDED = 1,
|
||||
DEVICE_REMOVED = 2,
|
||||
STATUS_UPDATE_RECEIVED = 3,
|
||||
COMMAND_RECEIVED = 4,
|
||||
STATE_CHANGED = 5
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Base class for device events.
|
||||
*/
|
||||
@@ -33,20 +50,15 @@ class DeviceEvent {
|
||||
public:
|
||||
typedef std::chrono::system_clock::time_point timestamp_t;
|
||||
|
||||
enum class EventType : int {
|
||||
DEVICE_ADDED = 1,
|
||||
DEVICE_REMOVED = 2,
|
||||
STATUS_UPDATE_RECEIVED = 3,
|
||||
COMMAND_RECEIVED = 4,
|
||||
STATE_CHANGED = 5
|
||||
};
|
||||
DeviceEventType eventType;
|
||||
|
||||
|
||||
Device* const device;
|
||||
const timestamp_t timestamp;
|
||||
const EventType eventType;
|
||||
|
||||
DeviceEvent(Device* device, const EventType& type, const timestamp_t& timestamp)
|
||||
: device(device), timestamp(timestamp), eventType(type) {}
|
||||
const timestamp_t timestamp;
|
||||
|
||||
DeviceEvent(Device* device, const DeviceEventType& type, const timestamp_t& timestamp)
|
||||
: eventType(type), device(device), timestamp(timestamp) {}
|
||||
};
|
||||
|
||||
|
||||
@@ -58,7 +70,7 @@ class DeviceAddedEvent
|
||||
: public DeviceEvent {
|
||||
public:
|
||||
DeviceAddedEvent(Device* device, const timestamp_t& timestamp)
|
||||
: DeviceEvent(device, DeviceEvent::EventType::DEVICE_ADDED, timestamp) {}
|
||||
: DeviceEvent(device,DeviceEventType::DEVICE_ADDED, timestamp) {}
|
||||
};
|
||||
|
||||
|
||||
@@ -70,7 +82,7 @@ class DeviceRemovedEvent
|
||||
: public DeviceEvent {
|
||||
public:
|
||||
DeviceRemovedEvent(Device* device, const timestamp_t& timestamp)
|
||||
: DeviceEvent(device, DeviceEvent::EventType::DEVICE_REMOVED, timestamp) {}
|
||||
: DeviceEvent(device, DeviceEventType::DEVICE_REMOVED, timestamp) {}
|
||||
};
|
||||
|
||||
|
||||
@@ -84,7 +96,7 @@ public:
|
||||
const Variant statusMsg;
|
||||
|
||||
DeviceStatusMsgEvent(Device* device, const Variant& statusMsg, const timestamp_t& timestamp)
|
||||
: DeviceEvent(device, DeviceEvent::EventType::STATUS_UPDATE_RECEIVED, timestamp), statusMsg(statusMsg) {}
|
||||
: DeviceEvent(device, DeviceEventType::STATUS_UPDATE_RECEIVED, timestamp), statusMsg(statusMsg) {}
|
||||
};
|
||||
|
||||
|
||||
@@ -98,7 +110,7 @@ public:
|
||||
const Variant cmdMsg;
|
||||
|
||||
DeviceCmdMsgEvent(Device* device, const Variant& cmdMsg, const timestamp_t& timestamp)
|
||||
: DeviceEvent(device, DeviceEvent::EventType::COMMAND_RECEIVED, timestamp), cmdMsg(cmdMsg) {}
|
||||
: DeviceEvent(device, DeviceEventType::COMMAND_RECEIVED, timestamp), cmdMsg(cmdMsg) {}
|
||||
};
|
||||
|
||||
|
||||
@@ -112,33 +124,89 @@ public:
|
||||
const Variant statusMsg;
|
||||
|
||||
DeviceStateChangeEvent(Device* device, const Variant& statusMsg, const timestamp_t& timestamp)
|
||||
: DeviceEvent(device, DeviceEvent::EventType::STATE_CHANGED, timestamp), statusMsg(statusMsg) {}
|
||||
: DeviceEvent(device, DeviceEventType::STATE_CHANGED, timestamp), statusMsg(statusMsg) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Public COSGI interface of an device object.
|
||||
*
|
||||
* It offers following functionality:
|
||||
* - Get device informations.
|
||||
* - Events indicating device state changes.
|
||||
* - Send commands to the device.
|
||||
*/
|
||||
class Device
|
||||
: public virtual interface::ObservableObject<DeviceEvent::EventType, DeviceEvent> {
|
||||
: public virtual interface::ObservableObject<DeviceEventType, DeviceEvent> {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::chrono::system_clock::time_point timestamp_t;
|
||||
|
||||
/**
|
||||
* Returns the device identifier.
|
||||
*
|
||||
* \return unique device identifier.
|
||||
*/
|
||||
virtual const std::string& getDeviceID() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the device type.
|
||||
*
|
||||
* \return device type.
|
||||
*/
|
||||
virtual const std::string& getDeviceType() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the ROS topic the device uses for commands.
|
||||
*
|
||||
* \return command topic.
|
||||
*/
|
||||
virtual const std::string& getCmdTopic() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the ROS topic the device uses for status updates.
|
||||
*
|
||||
* \return status updates topic.
|
||||
*/
|
||||
virtual const std::string& getStatusTopic() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the current state of the device.
|
||||
*
|
||||
* \return current state.
|
||||
*/
|
||||
virtual const Variant& getCurrentState() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the timestamp of the current state.
|
||||
*
|
||||
* \return timestamp.
|
||||
*/
|
||||
virtual const timestamp_t& getCurrentStateTimestamp() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the last state of the device.
|
||||
*
|
||||
* \return last state.
|
||||
*/
|
||||
virtual const Variant& getLastState() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the timestamp of the last state.
|
||||
*
|
||||
* \return timestamp.
|
||||
*/
|
||||
virtual const timestamp_t& getLastStateTimestamp() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Sends a command to the device.
|
||||
*
|
||||
* May return exceptions derived from std::exception.
|
||||
*
|
||||
* \param[in] cmd command.
|
||||
*/
|
||||
virtual void sendCommand(const Variant& cmd) = 0;
|
||||
|
||||
};
|
||||
@@ -146,18 +214,49 @@ public:
|
||||
|
||||
|
||||
/**
|
||||
* Public COSGI interface of the device repository service
|
||||
**/
|
||||
* Public COSGI interface of the device repository service.
|
||||
*
|
||||
* It offers following functionality:
|
||||
* - Retrieve devices.
|
||||
* - Events indicating new/removed devices.
|
||||
*/
|
||||
class DeviceRepositoryService
|
||||
: public virtual interface::ObservableService<DeviceEvent::EventType, DeviceEvent> {
|
||||
: public virtual interface::ObservableService<DeviceEventType, DeviceEvent> {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* The service name.
|
||||
*/
|
||||
static constexpr const char* SERVICE_NAME = "hos_devicerepository_service";
|
||||
|
||||
/**
|
||||
* Retrieves the device with the given identifier.
|
||||
*
|
||||
* \param[in] device_id device identifier.
|
||||
* \return device pointer, or expired pointer when no device was found.
|
||||
*/
|
||||
virtual std::weak_ptr<Device> getDevice(const std::string& device_id) noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns all known devices.
|
||||
*
|
||||
* \return vector of device pointers.
|
||||
*/
|
||||
virtual std::vector<std::weak_ptr<Device>> getDevices() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the number of known devices.
|
||||
*
|
||||
* \return device count.
|
||||
*/
|
||||
virtual size_t deviceCount() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the device ids of known devices.
|
||||
*
|
||||
* \return vector of device pointers.
|
||||
*/
|
||||
virtual std::vector<std::string> getDeviceIDs() noexcept = 0;
|
||||
|
||||
};
|
||||
@@ -169,6 +268,3 @@ public:
|
||||
} // namespace cosgi
|
||||
} // namespace hos
|
||||
|
||||
|
||||
|
||||
#endif /* _HOS_DEVICEREPOSITORY_SERVICE_H_ */
|
||||
|
||||
@@ -1,41 +1,42 @@
|
||||
|
||||
// std
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
// ROS
|
||||
#include <ros/ros.h>
|
||||
// APR
|
||||
#include <apr_general.h>
|
||||
|
||||
#include "ros/ros.h"
|
||||
|
||||
extern "C" {
|
||||
#include "celix/bundle_activator.h"
|
||||
#include "celix/bundle_context.h"
|
||||
}
|
||||
|
||||
// Celix
|
||||
#include <hos/cosgi/celix.h>
|
||||
// CoreService
|
||||
#include <hos/cosgi/service/core/CoreService.h>
|
||||
#include "hos/cosgi/service/devicerepository/DeviceRepositoryServiceImpl.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
|
||||
using namespace hos::cosgi;
|
||||
using namespace hos::cosgi::service::devicerepository;
|
||||
|
||||
|
||||
|
||||
struct UserData {
|
||||
apr_pool_t* memoryPool = nullptr;
|
||||
std::unique_ptr<DeviceRepositoryServiceImpl> serviceImpl;
|
||||
service_registration_pt serviceReg = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
|
||||
celix_status_t status = CELIX_START_ERROR;
|
||||
apr_pool_t* memoryPool = nullptr;
|
||||
|
||||
// Create APR memory pool
|
||||
apr_status_t astatus = apr_pool_create(&memoryPool, NULL);
|
||||
if (astatus != APR_SUCCESS) {
|
||||
ROS_ERROR("DeviceRepositoryService: Could not create APR memory pool (%i).", astatus);
|
||||
} else {
|
||||
|
||||
// Create user data
|
||||
UserData* myUserData = (UserData*)apr_palloc(memoryPool, sizeof(UserData));
|
||||
if (myUserData != nullptr) {
|
||||
@@ -47,20 +48,24 @@ celix_status_t bundleActivator_create(bundle_context_pt context, void **userData
|
||||
ROS_ERROR("DeviceRepositoryService: Could not create user data struct");
|
||||
apr_pool_destroy(memoryPool);
|
||||
}
|
||||
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
|
||||
celix_status_t status = CELIX_SUCCESS;
|
||||
if (userData != nullptr) {
|
||||
UserData* myUserData = (UserData*)userData;
|
||||
// Create hos-devicerepository-service
|
||||
|
||||
// Create device repository service
|
||||
if (myUserData->serviceReg != nullptr) {
|
||||
serviceRegistration_unregister(myUserData->serviceReg);
|
||||
}
|
||||
myUserData->serviceImpl.reset(new DeviceRepositoryServiceImpl());
|
||||
// Get HOS Core Service
|
||||
|
||||
// Get core service
|
||||
service_reference_pt ref = nullptr;
|
||||
bundleContext_getServiceReference(context, (char*)service::core::CoreService::SERVICE_NAME, &ref);
|
||||
service::core::CoreService* coreService = nullptr;
|
||||
@@ -70,10 +75,12 @@ celix_status_t bundleActivator_start(void * userData, bundle_context_pt context)
|
||||
} else {
|
||||
myUserData->serviceImpl->setCoreService(coreService);
|
||||
}
|
||||
// Register hos-devicerepository-service
|
||||
|
||||
// Register device repository service
|
||||
if (myUserData->serviceImpl->isInitialized()) {
|
||||
bundleContext_registerService(context, (char*)DeviceRepositoryService::SERVICE_NAME, myUserData->serviceImpl.get(), nullptr, &myUserData->serviceReg);
|
||||
}
|
||||
|
||||
ROS_INFO("DeviceRepositoryService: Bundle successfully started");
|
||||
} else {
|
||||
ROS_ERROR("DeviceRepositoryService: Could not start bundle, user data struct is null");
|
||||
@@ -81,6 +88,7 @@ celix_status_t bundleActivator_start(void * userData, bundle_context_pt context)
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) {
|
||||
celix_status_t status = CELIX_ILLEGAL_STATE;
|
||||
if (userData != nullptr) {
|
||||
@@ -100,6 +108,7 @@ celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context)
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
|
||||
celix_status_t status = CELIX_ILLEGAL_STATE;
|
||||
if (userData != nullptr) {
|
||||
@@ -116,3 +125,4 @@ celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt contex
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
+139
-95
@@ -1,12 +1,5 @@
|
||||
/*
|
||||
* hos_itemrepository_service_impl.cpp
|
||||
*
|
||||
* Created on: 05.04.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#include "DeviceRepositoryServiceImpl.h"
|
||||
|
||||
#include <hos/cosgi/service/core/CoreService.h>
|
||||
#include <ros/ros.h>
|
||||
#include <exception>
|
||||
@@ -15,51 +8,65 @@
|
||||
|
||||
|
||||
|
||||
|
||||
// Service Namespace
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace devicerepository {
|
||||
|
||||
|
||||
|
||||
// Service information
|
||||
template<> const char* implementation::ServiceInfo<DeviceRepositoryServiceImpl>::name = service::devicerepository::DeviceRepositoryService::SERVICE_NAME;
|
||||
template<> const int implementation::ServiceInfo<DeviceRepositoryServiceImpl>::major = 1;
|
||||
template<> const int implementation::ServiceInfo<DeviceRepositoryServiceImpl>::minor = 0;
|
||||
|
||||
|
||||
bool DeviceImpl::handleStatusMsg(const Variant& msg, const timestamp_t& stamp) {
|
||||
|
||||
bool DeviceImpl::handleStatusMsg(const Variant& msg, const timestamp_t& stamp) noexcept {
|
||||
std::lock_guard<std::recursive_mutex> lock(objMutex);
|
||||
Variant tmp = currentState.Copy();
|
||||
tmp.Merge(msg);
|
||||
|
||||
bool stateChanged = false;
|
||||
if (tmp != currentState) { // state has changed
|
||||
lastState = currentState.Copy();
|
||||
lastStamp = currentStamp;
|
||||
currentState = std::move(tmp);
|
||||
Variant newstate = currentState.Copy();
|
||||
newstate.Merge(msg);
|
||||
|
||||
if (newstate != currentState) {
|
||||
lastState = std::move(currentState);
|
||||
lastStamp = std::move(currentStamp);
|
||||
currentState = std::move(newstate);
|
||||
currentStamp = stamp;
|
||||
stateChanged = true;
|
||||
}
|
||||
|
||||
DeviceStatusMsgEvent event(this, msg, stamp);
|
||||
notifyObservers(DeviceEvent::EventType::STATUS_UPDATE_RECEIVED, &event);
|
||||
notifyObservers(DeviceEventType::STATUS_UPDATE_RECEIVED, &event);
|
||||
|
||||
if (stateChanged){
|
||||
DeviceStateChangeEvent event(this, msg, stamp);
|
||||
notifyObservers(DeviceEvent::EventType::STATE_CHANGED, &event);
|
||||
notifyObservers(DeviceEventType::STATE_CHANGED, &event);
|
||||
}
|
||||
|
||||
return stateChanged;
|
||||
}
|
||||
|
||||
void DeviceImpl::handleCommandMsg(const Variant& msg, const timestamp_t& stamp) {
|
||||
|
||||
void DeviceImpl::handleCommandMsg(const Variant& msg, const timestamp_t& stamp) noexcept {
|
||||
std::lock_guard<std::recursive_mutex> lock(objMutex);
|
||||
DeviceCmdMsgEvent event(this, msg, stamp);
|
||||
notifyObservers(DeviceEvent::EventType::COMMAND_RECEIVED, &event);
|
||||
notifyObservers(DeviceEventType::COMMAND_RECEIVED, &event);
|
||||
}
|
||||
|
||||
|
||||
void DeviceImpl::sendCommand(const Variant& cmd) {
|
||||
std::lock_guard<std::recursive_mutex> lock(objMutex);
|
||||
parent->sendDeviceCommand(this, cmd);
|
||||
}
|
||||
|
||||
void DeviceRepositoryServiceImpl::setCoreService(service::core::CoreService* coreService) {
|
||||
|
||||
|
||||
|
||||
|
||||
void DeviceRepositoryServiceImpl::setCoreService(service::core::CoreService* coreService) noexcept {
|
||||
if (coreService && !this->coreService) {
|
||||
this->coreService = coreService;
|
||||
this->nodehandle = &coreService->getPrivateNodeHandle();
|
||||
@@ -70,11 +77,15 @@ void DeviceRepositoryServiceImpl::setCoreService(service::core::CoreService* cor
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceRepositoryServiceImpl::init() {
|
||||
|
||||
void DeviceRepositoryServiceImpl::init() noexcept {
|
||||
// Get public parameters
|
||||
nodehandle->getParam("device_repository_prefix", deviceRepositoryPrefix);
|
||||
nodehandle->getParam("hos_status_topic", hosStatusTopic);
|
||||
XmlRpc::XmlRpcValue rawValue;
|
||||
nodehandle->getParam(deviceRepositoryPrefix, rawValue);
|
||||
|
||||
// create devices
|
||||
if (rawValue.getType() == XmlRpc::XmlRpcValue::TypeStruct) {
|
||||
for (auto dev : rawValue) {
|
||||
std::string devname = dev.first;
|
||||
@@ -87,11 +98,13 @@ void DeviceRepositoryServiceImpl::init() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hosStatusSub = nodehandle->subscribe(hosStatusTopic, 1000, &DeviceRepositoryServiceImpl::hosStatusMsgCallback, this);
|
||||
initialized = true;
|
||||
ROS_INFO_STREAM("DeviceRepositoryService: Initialized and Ready.");
|
||||
}
|
||||
|
||||
|
||||
void DeviceRepositoryServiceImpl::addDevice(const std::string& name) {
|
||||
std::stringstream ss;
|
||||
ss << deviceRepositoryPrefix << "/" << name;
|
||||
@@ -100,28 +113,37 @@ void DeviceRepositoryServiceImpl::addDevice(const std::string& name) {
|
||||
addDevice(name, rawValue);
|
||||
}
|
||||
|
||||
|
||||
void DeviceRepositoryServiceImpl::addDevice(const std::string& name, XmlRpc::XmlRpcValue& rawValue) {
|
||||
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||
std::string type, statusTopic, cmdTopic;
|
||||
|
||||
// device type
|
||||
XmlRpc::XmlRpcValue& typeRaw = rawValue["type"];
|
||||
if (typeRaw.getType() != XmlRpc::XmlRpcValue::TypeString) {
|
||||
throw std::runtime_error("type is not a string.");
|
||||
}
|
||||
type = static_cast<std::string>(typeRaw);
|
||||
type = static_cast<std::string>(typeRaw);
|
||||
|
||||
// device status topic
|
||||
XmlRpc::XmlRpcValue& statusTopicRaw = rawValue["status_topic"];
|
||||
if (statusTopicRaw.getType() != XmlRpc::XmlRpcValue::TypeString) {
|
||||
throw std::runtime_error("statusTopic is not a string.");
|
||||
}
|
||||
statusTopic = static_cast<std::string>(statusTopicRaw);
|
||||
|
||||
// device command topic
|
||||
XmlRpc::XmlRpcValue& cmdTopicRaw = rawValue["cmd_topic"];
|
||||
if (cmdTopicRaw.getType() != XmlRpc::XmlRpcValue::TypeString) {
|
||||
throw std::runtime_error("cmdTopic is not a string.");
|
||||
}
|
||||
cmdTopic = static_cast<std::string>(cmdTopicRaw);
|
||||
|
||||
// create device
|
||||
std::shared_ptr<DeviceImpl> dev = std::make_shared<DeviceImpl>(this, name, type, statusTopic, cmdTopic);
|
||||
devices.insert({name, dev});
|
||||
|
||||
// status topic
|
||||
// status topic subscriber
|
||||
auto& entry = subscripedTopics[dev->getStatusTopic()];
|
||||
if (entry.first <= 0) {
|
||||
entry.second = nodehandle->subscribe(dev->getStatusTopic(), 1000, &DeviceRepositoryServiceImpl::statusMsgCallback, this);
|
||||
@@ -130,7 +152,7 @@ void DeviceRepositoryServiceImpl::addDevice(const std::string& name, XmlRpc::Xml
|
||||
subscripedTopics[dev->getStatusTopic()] = entry;
|
||||
}
|
||||
|
||||
// cmd topic
|
||||
// cmd topic subscriber
|
||||
auto& entry2 = subscripedTopics[dev->getCmdTopic()];
|
||||
if (entry2.first <= 0) {
|
||||
entry2.second = nodehandle->subscribe(dev->getCmdTopic(), 1000, &DeviceRepositoryServiceImpl::cmdMsgCallback, this);
|
||||
@@ -139,7 +161,7 @@ void DeviceRepositoryServiceImpl::addDevice(const std::string& name, XmlRpc::Xml
|
||||
subscripedTopics[dev->getCmdTopic()] = entry2;
|
||||
}
|
||||
|
||||
// cmd publisher
|
||||
// cmd topic publisher
|
||||
auto& entry3 = publishedTopics[dev->getCmdTopic()];
|
||||
if (entry3.first <= 0) {
|
||||
entry3.second = nodehandle->advertise<hos_core_msgs::DeviceCommand>(dev->getCmdTopic(), 1000);
|
||||
@@ -148,13 +170,9 @@ void DeviceRepositoryServiceImpl::addDevice(const std::string& name, XmlRpc::Xml
|
||||
publishedTopics[dev->getCmdTopic()] = entry3;
|
||||
}
|
||||
|
||||
|
||||
entry2.first= entry2.first + 1;
|
||||
subscripedTopics[dev->getCmdTopic()] = entry2;
|
||||
|
||||
// send device added event
|
||||
DeviceAddedEvent event(dev.get(), std::chrono::system_clock::now());
|
||||
notifyObservers(DeviceEvent::EventType::DEVICE_ADDED, &event);
|
||||
notifyObservers(DeviceEventType::DEVICE_ADDED, &event);
|
||||
}
|
||||
|
||||
|
||||
@@ -163,8 +181,8 @@ void DeviceRepositoryServiceImpl::removeDevice(const std::string& name) {
|
||||
auto dev = devices.find(name);
|
||||
if (dev != devices.end()) {
|
||||
DeviceRemovedEvent event(dev->second.get(), std::chrono::system_clock::now());
|
||||
notifyObservers(DeviceEvent::EventType::DEVICE_REMOVED, &event);
|
||||
dev->second->notifyObservers(DeviceEvent::EventType::DEVICE_REMOVED, &event);
|
||||
notifyObservers(DeviceEventType::DEVICE_REMOVED, &event);
|
||||
dev->second->notifyObservers(DeviceEventType::DEVICE_REMOVED, &event);
|
||||
devices.erase(name);
|
||||
}
|
||||
}
|
||||
@@ -178,6 +196,7 @@ std::weak_ptr<Device> DeviceRepositoryServiceImpl::getDevice(const std::string&
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::weak_ptr<Device>> DeviceRepositoryServiceImpl::getDevices() noexcept {
|
||||
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||
std::vector<std::weak_ptr<Device>> retval;
|
||||
@@ -188,11 +207,6 @@ std::vector<std::weak_ptr<Device>> DeviceRepositoryServiceImpl::getDevices() noe
|
||||
}
|
||||
|
||||
|
||||
size_t DeviceRepositoryServiceImpl::deviceCount() noexcept {
|
||||
return devices.size();
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> DeviceRepositoryServiceImpl::getDeviceIDs() noexcept {
|
||||
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||
std::vector<std::string> retval;
|
||||
@@ -203,90 +217,117 @@ std::vector<std::string> DeviceRepositoryServiceImpl::getDeviceIDs() noexcept {
|
||||
}
|
||||
|
||||
|
||||
void DeviceRepositoryServiceImpl::statusMsgCallback(const hos_core_msgs::DeviceStatusUpdate::ConstPtr& msg) {
|
||||
void DeviceRepositoryServiceImpl::statusMsgCallback(const hos_core_msgs::DeviceStatusUpdate::ConstPtr& msg) noexcept {
|
||||
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||
std::cout << "HOSDeviceRepositoryServiceImpl::statusMsgCallback" << std::endl;
|
||||
Variant s = coreService->getSchemaLoader().GetSchema(std::string("hos:schema://").append(msg->device_type).append("/status"));
|
||||
Variant m = Deserialize(msg->msg_body, SERIALIZE_JSON);
|
||||
SchemaResult sr = SchemaValidate(s, m, &coreService->getSchemaLoader());
|
||||
if (!sr.Error()) {
|
||||
auto dev = devices.find(msg->device_id);
|
||||
if (dev != devices.end()) {
|
||||
auto stamp = std::chrono::system_clock::now();
|
||||
bool stateChanged = dev->second->handleStatusMsg(m, stamp);
|
||||
DeviceStatusMsgEvent event(dev->second.get(), m, stamp);
|
||||
notifyObservers(DeviceEvent::EventType::STATUS_UPDATE_RECEIVED, &event);
|
||||
if (stateChanged) {
|
||||
DeviceStateChangeEvent event(dev->second.get(), m, stamp);
|
||||
notifyObservers(DeviceEvent::EventType::STATE_CHANGED, &event);
|
||||
|
||||
try {
|
||||
// Verify message using appropriate json schema.
|
||||
auto schemaUrl = (boost::format("hos:schema://%1%/status") % msg->device_type).str();
|
||||
Variant s = coreService->getSchemaLoader().GetSchema(schemaUrl);
|
||||
Variant m = Deserialize(msg->msg_body, SERIALIZE_JSON);
|
||||
SchemaResult sr = SchemaValidate(s, m, &coreService->getSchemaLoader());
|
||||
if (!sr.Error()) {
|
||||
|
||||
// Get recipient and pass on message
|
||||
auto dev = devices.find(msg->device_id);
|
||||
if (dev != devices.end()) {
|
||||
auto stamp = std::chrono::system_clock::now();
|
||||
dev->second->handleStatusMsg(m, stamp);
|
||||
}
|
||||
|
||||
} else {
|
||||
ROS_ERROR_STREAM("Could not validate status message: " << sr.PrettyPrintMessage());
|
||||
}
|
||||
} else {
|
||||
ROS_ERROR_STREAM("Could not validate status message: " << sr.PrettyPrintMessage());
|
||||
} catch (std::exception& e) {
|
||||
ROS_ERROR_STREAM("Exception while handling device status message: " << e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceRepositoryServiceImpl::cmdMsgCallback(const hos_core_msgs::DeviceCommand::ConstPtr& msg) {
|
||||
|
||||
void DeviceRepositoryServiceImpl::cmdMsgCallback(const hos_core_msgs::DeviceCommand::ConstPtr& msg) noexcept {
|
||||
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||
std::cout << "HOSDeviceRepositoryServiceImpl::cmdMsgCallback" << std::endl;
|
||||
Variant s = coreService->getSchemaLoader().GetSchema(std::string("hos:schema://").append(msg->device_type).append("/command"));
|
||||
Variant m = Deserialize(msg->msg_body, SERIALIZE_JSON);
|
||||
auto test = msg->stamp;
|
||||
SchemaResult sr = SchemaValidate(s, m, &coreService->getSchemaLoader());
|
||||
if (!sr.Error()) {
|
||||
auto dev = devices.find(msg->device_id);
|
||||
if (dev != devices.end()) {
|
||||
auto stamp = std::chrono::system_clock::now();
|
||||
dev->second->handleCommandMsg(m, stamp);
|
||||
DeviceCmdMsgEvent event(dev->second.get(), m, stamp);
|
||||
notifyObservers(DeviceEvent::EventType::STATUS_UPDATE_RECEIVED, &event);
|
||||
|
||||
try {
|
||||
// Verify message using appropriate json schema.
|
||||
auto schemaUrl = (boost::format("hos:schema://%1%/command") % msg->device_type).str();
|
||||
Variant s = coreService->getSchemaLoader().GetSchema(schemaUrl);
|
||||
Variant m = Deserialize(msg->msg_body, SERIALIZE_JSON);
|
||||
auto test = msg->stamp;
|
||||
SchemaResult sr = SchemaValidate(s, m, &coreService->getSchemaLoader());
|
||||
if (!sr.Error()) {
|
||||
|
||||
// Get recipient and pass on message
|
||||
auto dev = devices.find(msg->device_id);
|
||||
if (dev != devices.end()) {
|
||||
auto stamp = std::chrono::system_clock::now();
|
||||
dev->second->handleCommandMsg(m, stamp);
|
||||
}
|
||||
|
||||
} else {
|
||||
ROS_ERROR_STREAM("Could not validate command message: " << sr.PrettyPrintMessage());
|
||||
}
|
||||
} else {
|
||||
ROS_ERROR_STREAM("Could not validate command message: " << sr.PrettyPrintMessage());
|
||||
} catch (std::exception& e) {
|
||||
ROS_ERROR_STREAM("Exception while handling device command message: " << e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceRepositoryServiceImpl::hosStatusMsgCallback(const hos_core_msgs::HosStatusUpdate::ConstPtr& msg) {
|
||||
|
||||
void DeviceRepositoryServiceImpl::hosStatusMsgCallback(const hos_core_msgs::HosStatusUpdate::ConstPtr& msg) noexcept {
|
||||
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||
std::cout << "HOSDeviceRepositoryServiceImpl::hosStatusMsgCallback" << std::endl;
|
||||
Variant s = coreService->getSchemaLoader().GetSchema(std::string("hos:schema://core/msgs/hosstatusupdate"));
|
||||
Variant m = Deserialize(msg->msg_body, SERIALIZE_JSON);
|
||||
SchemaResult sr = SchemaValidate(s, m, &coreService->getSchemaLoader());
|
||||
if (!sr.Error()) {
|
||||
if (m.Contains("devices")) {
|
||||
auto d = m["devices"];
|
||||
if (d.Contains("added") && d["added"].IsList()) {
|
||||
for (auto dev : d["added"].AsList()) {
|
||||
if (dev.IsString()) {
|
||||
std::string devname = dev.AsString();
|
||||
if (devices.find(devname) == devices.end()) {
|
||||
addDevice(devname);
|
||||
|
||||
try {
|
||||
// Verify message using appropriate json schema.
|
||||
Variant s = coreService->getSchemaLoader().GetSchema(std::string("hos:schema://core/msgs/hosstatusupdate"));
|
||||
Variant m = Deserialize(msg->msg_body, SERIALIZE_JSON);
|
||||
SchemaResult sr = SchemaValidate(s, m, &coreService->getSchemaLoader());
|
||||
if (!sr.Error()) {
|
||||
|
||||
// we are only interested in the device part.
|
||||
if (m.Contains("devices")) {
|
||||
auto d = m["devices"];
|
||||
// devices added
|
||||
if (d.Contains("added") && d["added"].IsList()) {
|
||||
for (auto dev : d["added"].AsList()) {
|
||||
if (dev.IsString()) {
|
||||
std::string devname = dev.AsString();
|
||||
if (devices.find(devname) == devices.end()) {
|
||||
addDevice(devname);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (d.Contains("removed") && d["removed"].IsList()) {
|
||||
for (auto dev : d["removed"].AsList()) {
|
||||
if (dev.IsString()) {
|
||||
std::string devname = dev.AsString();
|
||||
if (devices.find(devname) != devices.end()) {
|
||||
removeDevice(devname);
|
||||
// devices removed
|
||||
if (d.Contains("removed") && d["removed"].IsList()) {
|
||||
for (auto dev : d["removed"].AsList()) {
|
||||
if (dev.IsString()) {
|
||||
std::string devname = dev.AsString();
|
||||
if (devices.find(devname) != devices.end()) {
|
||||
removeDevice(devname);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
ROS_ERROR_STREAM("Could not validate hos status message: " << sr.PrettyPrintMessage());
|
||||
}
|
||||
} else {
|
||||
ROS_ERROR_STREAM("Could not validate hos status message: " << sr.PrettyPrintMessage());
|
||||
} catch (std::exception& e) {
|
||||
ROS_ERROR_STREAM("Exception while handling hos status message: " << e.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DeviceRepositoryServiceImpl::sendDeviceCommand(Device* device, const Variant& cmd) {
|
||||
void DeviceRepositoryServiceImpl::sendDeviceCommand(DeviceImpl* device, const Variant& cmd) {
|
||||
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||
|
||||
// Verify message using appropriate json schema.
|
||||
auto schemaUrl = (boost::format("hos:schema://%1%/command") % device->getDeviceType()).str();
|
||||
Variant s = coreService->getSchemaLoader().GetSchema(schemaUrl);
|
||||
SchemaResult sr = SchemaValidate(s, cmd, &coreService->getSchemaLoader());
|
||||
if (!sr.Error()) {
|
||||
|
||||
// Retrieve appropriate publisher and send message
|
||||
auto entry = publishedTopics[device->getCmdTopic()];
|
||||
if (entry.first > 0) {
|
||||
hos_core_msgs::DeviceCommand command;
|
||||
@@ -296,11 +337,14 @@ void DeviceRepositoryServiceImpl::sendDeviceCommand(Device* device, const Varian
|
||||
command.msg_body = Serialize(cmd, SERIALIZE_JSON);
|
||||
command.stamp = ros::Time::now();
|
||||
entry.second.publish(command);
|
||||
|
||||
} else {
|
||||
ROS_ERROR_STREAM("Could not find device command publisher for topic " << device->getCmdTopic());
|
||||
auto msg = (boost::format("Could not find device command publisher for topic %1%") % device->getCmdTopic()).str();
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
} else {
|
||||
ROS_ERROR_STREAM("Could not validate device command: " << sr.PrettyPrintMessage());
|
||||
auto msg = (boost::format("Could not validate device command: %1%") % sr.PrettyPrintMessage()).str();
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+94
-48
@@ -1,27 +1,25 @@
|
||||
/*
|
||||
* hos_itemrepository_service_impl.h
|
||||
*
|
||||
* Created on: 05.04.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#ifndef SRC_HOS_COSGI_SERVICE_DEVICEREPOSITORY_DEVICEREPOSITORY_SERVICEIMPL_H_
|
||||
#define SRC_HOS_COSGI_SERVICE_DEVICEREPOSITORY_DEVICEREPOSITORY_SERVICEIMPL_H_
|
||||
#pragma once
|
||||
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
// hos includes
|
||||
#include <hos/cosgi/service/core/CoreService.h>
|
||||
#include <hos/cosgi/service/Implementation.h>
|
||||
#include <hos_core_msgs/DeviceCommand.h>
|
||||
#include <hos_core_msgs/DeviceStatusUpdate.h>
|
||||
#include <hos_core_msgs/HosStatusUpdate.h>
|
||||
#include <hos/utils/SchemaLoader.h>
|
||||
// libvariant includes
|
||||
#include <Variant/Variant.h>
|
||||
// ROS includes
|
||||
#include <ros/ros.h>
|
||||
// std includes
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <hos_core_msgs/DeviceCommand.h>
|
||||
#include <hos_core_msgs/DeviceStatusUpdate.h>
|
||||
#include <hos_core_msgs/HosStatusUpdate.h>
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include <hos/cosgi/service/core/CoreService.h>
|
||||
#include <hos/cosgi/service/Implementation.h>
|
||||
#include <ros/ros.h>
|
||||
|
||||
|
||||
using namespace libvariant;
|
||||
@@ -29,10 +27,15 @@ using namespace libvariant;
|
||||
|
||||
|
||||
namespace std {
|
||||
/**
|
||||
* Specialization of std::hash for DeviceEventType.
|
||||
*
|
||||
* Required by std::map.
|
||||
*/
|
||||
template <>
|
||||
class hash <hos::cosgi::service::devicerepository::DeviceEvent::EventType>{
|
||||
class hash <hos::cosgi::service::devicerepository::DeviceEventType>{
|
||||
public :
|
||||
size_t operator()(const hos::cosgi::service::devicerepository::DeviceEvent::EventType& x) const {
|
||||
size_t operator()(const hos::cosgi::service::devicerepository::DeviceEventType& x) const {
|
||||
return static_cast<size_t>(x);
|
||||
}
|
||||
};
|
||||
@@ -52,22 +55,26 @@ class DeviceRepositoryServiceImpl;
|
||||
|
||||
|
||||
/**
|
||||
* Device implementation
|
||||
* Implementation of Device.
|
||||
**/
|
||||
class DeviceImpl
|
||||
: public virtual Device,
|
||||
public virtual implementation::ObservableObject<DeviceEvent::EventType, DeviceEvent> {
|
||||
public virtual implementation::ObservableObject<DeviceEventType, DeviceEvent> {
|
||||
|
||||
private:
|
||||
|
||||
DeviceRepositoryServiceImpl* parent;
|
||||
std::recursive_mutex objMutex;
|
||||
|
||||
std::string deviceID;
|
||||
std::string deviceType;
|
||||
|
||||
std::string statusTopic;
|
||||
std::string cmdTopic;
|
||||
|
||||
Variant currentState;
|
||||
timestamp_t currentStamp;
|
||||
|
||||
Variant lastState;
|
||||
timestamp_t lastStamp;
|
||||
|
||||
@@ -77,26 +84,46 @@ public:
|
||||
const std::string& deviceType,
|
||||
const std::string& statusTopic,
|
||||
const std::string& cmdTopic )
|
||||
: parent(parent), deviceID(deviceID), deviceType(deviceType), statusTopic(statusTopic), cmdTopic(cmdTopic) {}
|
||||
: parent(parent), deviceID(deviceID), deviceType(deviceType),
|
||||
statusTopic(statusTopic), cmdTopic(cmdTopic) {}
|
||||
|
||||
|
||||
/* Public Service Implementations */
|
||||
|
||||
virtual const std::string& getDeviceID() noexcept override { return deviceID; }
|
||||
virtual const std::string& getDeviceType() noexcept override { return deviceType; }
|
||||
virtual const std::string& getCmdTopic() noexcept override { return cmdTopic; }
|
||||
virtual const std::string& getStatusTopic() noexcept override { return statusTopic; }
|
||||
virtual const std::string& getDeviceID() noexcept override {
|
||||
return deviceID;
|
||||
}
|
||||
virtual const std::string& getDeviceType() noexcept override {
|
||||
return deviceType;
|
||||
}
|
||||
virtual const std::string& getCmdTopic() noexcept override {
|
||||
return cmdTopic;
|
||||
}
|
||||
virtual const std::string& getStatusTopic() noexcept override {
|
||||
return statusTopic;
|
||||
}
|
||||
|
||||
virtual const Variant& getCurrentState() noexcept override { return currentState; }
|
||||
virtual const timestamp_t& getCurrentStateTimestamp() noexcept override { return currentStamp; }
|
||||
virtual const Variant& getLastState() noexcept override { return lastState; }
|
||||
virtual const timestamp_t& getLastStateTimestamp() noexcept override { return lastStamp; }
|
||||
virtual const Variant& getCurrentState() noexcept override {
|
||||
return currentState;
|
||||
}
|
||||
virtual const timestamp_t& getCurrentStateTimestamp() noexcept override {
|
||||
return currentStamp;
|
||||
}
|
||||
virtual const Variant& getLastState() noexcept override {
|
||||
return lastState;
|
||||
}
|
||||
virtual const timestamp_t& getLastStateTimestamp() noexcept override {
|
||||
return lastStamp;
|
||||
}
|
||||
|
||||
virtual void sendCommand(const Variant& cmd) override;
|
||||
|
||||
/* Internal Stuff */
|
||||
|
||||
bool handleStatusMsg(const Variant& msg, const timestamp_t& stamp);
|
||||
void handleCommandMsg(const Variant& msg, const timestamp_t& stamp);
|
||||
/* Internal */
|
||||
|
||||
bool handleStatusMsg(const Variant& msg, const timestamp_t& stamp) noexcept;
|
||||
|
||||
void handleCommandMsg(const Variant& msg, const timestamp_t& stamp) noexcept;
|
||||
};
|
||||
|
||||
|
||||
@@ -107,9 +134,12 @@ public:
|
||||
**/
|
||||
class DeviceRepositoryServiceImpl
|
||||
: public virtual DeviceRepositoryService,
|
||||
public virtual implementation::ObservableService<DeviceRepositoryServiceImpl, DeviceEvent::EventType, DeviceEvent> {
|
||||
public virtual implementation::ObservableService<DeviceRepositoryServiceImpl, DeviceEventType, DeviceEvent> {
|
||||
|
||||
private:
|
||||
typedef std::map<std::string, std::shared_ptr<DeviceImpl>> devicesMap_t;
|
||||
typedef std::map<std::string, std::pair<int, ros::Subscriber>> subscripedTopicMap_t;
|
||||
typedef std::map<std::string, std::pair<int, ros::Publisher>> publishedTopicMap_t;
|
||||
|
||||
std::recursive_mutex serviceMutex;
|
||||
|
||||
@@ -119,52 +149,68 @@ private:
|
||||
std::string deviceRepositoryPrefix = "/hos/devices/repository";
|
||||
std::string hosStatusTopic = "/hos/status/updates";
|
||||
|
||||
typedef std::map<std::string, std::shared_ptr<DeviceImpl>> devicesMap_t;
|
||||
devicesMap_t devices;
|
||||
typedef std::map<std::string, std::pair<int, ros::Subscriber>> subscripedTopicMap_t;
|
||||
typedef std::map<std::string, std::pair<int, ros::Publisher>> publishedTopicMap_t;
|
||||
|
||||
subscripedTopicMap_t subscripedTopics;
|
||||
publishedTopicMap_t publishedTopics;
|
||||
long msgSeqNumber = 0;
|
||||
ros::Subscriber hosStatusSub;
|
||||
long msgSeqNumber = 0;
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
void init();
|
||||
void init() noexcept;
|
||||
|
||||
void addDevice(const std::string& name);
|
||||
|
||||
void addDevice(const std::string& name, XmlRpc::XmlRpcValue& rawValue);
|
||||
|
||||
void removeDevice(const std::string& name);
|
||||
|
||||
public:
|
||||
/* Initialization */
|
||||
|
||||
void setCoreService(service::core::CoreService* coreService);
|
||||
void setCoreService(service::core::CoreService* coreService) noexcept;
|
||||
|
||||
|
||||
/* Public Service Implementations */
|
||||
|
||||
virtual std::weak_ptr<Device> getDevice(const std::string& device_id) noexcept override;
|
||||
|
||||
virtual std::vector<std::weak_ptr<Device>> getDevices() noexcept override;
|
||||
virtual size_t deviceCount() noexcept override;
|
||||
|
||||
virtual size_t deviceCount() noexcept override {
|
||||
return devices.size();
|
||||
}
|
||||
|
||||
virtual std::vector<std::string> getDeviceIDs() noexcept override;
|
||||
|
||||
|
||||
/* Message Callbacks */
|
||||
|
||||
void statusMsgCallback(const hos_core_msgs::DeviceStatusUpdate::ConstPtr& msg);
|
||||
void cmdMsgCallback(const hos_core_msgs::DeviceCommand::ConstPtr& msg);
|
||||
void hosStatusMsgCallback(const hos_core_msgs::HosStatusUpdate::ConstPtr& msg);
|
||||
/** ROS subscriber callback for device status messages. */
|
||||
void statusMsgCallback(const hos_core_msgs::DeviceStatusUpdate::ConstPtr& msg) noexcept;
|
||||
|
||||
/* Internal Stuff */
|
||||
/** ROS subscriber callback for device command messages. */
|
||||
void cmdMsgCallback(const hos_core_msgs::DeviceCommand::ConstPtr& msg) noexcept;
|
||||
|
||||
/** ROS subscriber callback for hos status messages. */
|
||||
void hosStatusMsgCallback(const hos_core_msgs::HosStatusUpdate::ConstPtr& msg) noexcept;
|
||||
|
||||
|
||||
/* Internal */
|
||||
|
||||
bool isInitialized() noexcept {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void sendDeviceCommand(DeviceImpl* device, const Variant& cmd);
|
||||
|
||||
bool isInitialized() noexcept { return initialized; }
|
||||
void sendDeviceCommand(Device* device, const Variant& cmd);
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace devicerepository
|
||||
} // namespace service
|
||||
} // namespace cosgi
|
||||
} // namespace hos
|
||||
|
||||
|
||||
#endif /* SRC_HOS_COSGI_SERVICE_DEVICEREPOSITORY_DEVICEREPOSITORY_SERVICEIMPL_H_ */
|
||||
|
||||
@@ -120,11 +120,14 @@ set(BUNDLE_NAME "hos_ruleengine")
|
||||
|
||||
bundle(hos_cosgi_ruleengine
|
||||
SOURCES
|
||||
${PROJECT_SOURCE_DIR}/src/bundle_activator
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/ruleengine_serviceimpl
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rule/RulePackage
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rule/Rule
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rule/RuleConditionImpl
|
||||
${PROJECT_SOURCE_DIR}/src/BundleActivator
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/RuleEngineServiceImpl
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/RulePackageImpl
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/RuleImpl
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/conditions/RuleConditionImpl
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/conditions/LogicalOrCondition
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/conditions/LogicalAndCondition
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/conditions/DeviceMsgCondition
|
||||
)
|
||||
target_link_libraries(hos_cosgi_ruleengine
|
||||
${catkin_LIBRARIES}
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
#include <hos/cosgi/service/Interface.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
|
||||
// forward declarations
|
||||
namespace libvariant { class Variant; }
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
|
||||
|
||||
// forward declarations
|
||||
namespace rules {
|
||||
class RulePackage;
|
||||
class Rule;
|
||||
namespace conditions { class RuleCondition; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Public abstract COSGI interface of a rule condition factory.
|
||||
*/
|
||||
class RuleConditionFactory
|
||||
: public virtual interface::Object {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates and returns a condition from the given json config.
|
||||
*
|
||||
* \param[in] parent parent rule
|
||||
* \param[in] json config
|
||||
* \return new rule condition
|
||||
*/
|
||||
virtual std::shared_ptr<rules::conditions::RuleCondition> createCondition(rules::Rule* parent, const libvariant::Variant& raw) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Public COSGI interface of the rule engine service.
|
||||
*/
|
||||
class RuleEngineService
|
||||
: public virtual interface::Service {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* The service name.
|
||||
*/
|
||||
static constexpr const char* SERVICE_NAME = "hos_ruleengine_service";
|
||||
|
||||
/**
|
||||
* Returns the rulepackage with the given name.
|
||||
*
|
||||
* \param[in] name name
|
||||
* \return weak reference to rule package (an expired reference is returned if the wanted rule package does not exists).
|
||||
*/
|
||||
virtual std::weak_ptr<rules::RulePackage> getRulePackage(const std::string& name) noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns a vector containing all known rulepackages.
|
||||
*
|
||||
* \return vector of weak references.
|
||||
*/
|
||||
virtual std::vector<std::weak_ptr<rules::RulePackage>> getRulePackages() noexcept = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of known rule packages.
|
||||
*
|
||||
* \return rule package count.
|
||||
*/
|
||||
virtual size_t getRulePackageCount() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Registers a rule condition factory under the given type identifier.
|
||||
*
|
||||
* \param[in] type condition type identifier.
|
||||
* \param[in] factory rule condition factory.
|
||||
*/
|
||||
virtual void registerRuleConditionFactory(const std::string& type, std::shared_ptr<RuleConditionFactory> factory) noexcept = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace ruleengine
|
||||
} // namespace service
|
||||
} // namespace cosgi
|
||||
} // namespace hos
|
||||
|
||||
|
||||
-94
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Rule.h
|
||||
*
|
||||
* Created on: 29.04.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#ifndef SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULE_H_
|
||||
#define SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULE_H_
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <Variant/Variant.h>
|
||||
#include "RuleCondition.h"
|
||||
|
||||
|
||||
// Forward declarations
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace devicerepository {
|
||||
class Device;
|
||||
class DeviceEvent;
|
||||
class DeviceRepositoryService;
|
||||
}
|
||||
namespace ruleengine {
|
||||
namespace rule {
|
||||
class RulePackage;
|
||||
}
|
||||
}
|
||||
namespace scripting {
|
||||
class ScriptingService;
|
||||
class GlobalScriptContext;
|
||||
class Script;
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace utils {
|
||||
class SchemaLoader;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rule {
|
||||
|
||||
using namespace ::libvariant;
|
||||
|
||||
class Rule {
|
||||
private:
|
||||
std::shared_ptr<scripting::Script> script;
|
||||
std::shared_ptr<scripting::Script> exitScript;
|
||||
std::shared_ptr<RuleCondition> condition;
|
||||
bool enabled = false;
|
||||
bool currentState = false;
|
||||
|
||||
public:
|
||||
RulePackage* const parent;
|
||||
const std::string name;
|
||||
|
||||
Rule(RulePackage* parent, const std::string name);
|
||||
static std::shared_ptr<Rule> createRule(RulePackage* parent, const std::string name, Variant raw);
|
||||
|
||||
bool getCurrentState() { return currentState; }
|
||||
bool evaluate();
|
||||
void execute(Variant lContext = Variant());
|
||||
void executeExitScript(Variant lContext = Variant());
|
||||
|
||||
bool isEnabled() { return enabled; }
|
||||
void enable();
|
||||
void disable();
|
||||
|
||||
void conditionStateChanged(bool newState, RuleCondition::Category category, Variant lcontext = Variant());
|
||||
|
||||
std::shared_ptr<RuleCondition> createRuleCondition(Variant raw);
|
||||
|
||||
utils::SchemaLoader* getHOSSchemaLoader();
|
||||
devicerepository::DeviceRepositoryService* getDeviceRepository();
|
||||
};
|
||||
|
||||
|
||||
} /* namespace rule */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
|
||||
#endif /* SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULE_H_ */
|
||||
-105
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* RuleCondition.h
|
||||
*
|
||||
* Created on: 29.04.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#ifndef SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULECONDITION_H_
|
||||
#define SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULECONDITION_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rule {
|
||||
|
||||
class Rule;
|
||||
class RuleCompositeCondition;
|
||||
|
||||
using namespace ::libvariant;
|
||||
|
||||
|
||||
class RuleCondition {
|
||||
public:
|
||||
enum class Category : int { Event, State, Mixed };
|
||||
|
||||
protected:
|
||||
bool currentState = false;
|
||||
Category category;
|
||||
RuleCompositeCondition* compositeParent = nullptr;
|
||||
bool enabled = false;
|
||||
|
||||
void notifyStateChangeToParent(bool newState, Category category, Variant lcontext = Variant());
|
||||
|
||||
public:
|
||||
Rule* const parent;
|
||||
const std::string type;
|
||||
|
||||
RuleCondition(Rule* parent, Category category, const std::string type) :
|
||||
parent(parent), category(category), type(type) {}
|
||||
virtual ~RuleCondition() {}
|
||||
void setCompositeParent(RuleCompositeCondition* compositeParent) {
|
||||
this->compositeParent = compositeParent;
|
||||
}
|
||||
|
||||
virtual Category getCategory() { return category; }
|
||||
|
||||
bool getCurrentState() { return currentState; }
|
||||
virtual bool evaluate() { return currentState; }
|
||||
|
||||
bool isEnabled() { return enabled; }
|
||||
virtual void enable() { enabled = true; }
|
||||
virtual void disable() { enabled = false; }
|
||||
};
|
||||
|
||||
|
||||
class RuleCompositeCondition : public RuleCondition {
|
||||
protected:
|
||||
std::vector<std::shared_ptr<RuleCondition>> children;
|
||||
public:
|
||||
RuleCompositeCondition(Rule* parent, Category category, std::string type) :
|
||||
RuleCondition(parent, category, type) {}
|
||||
|
||||
virtual void childStateChanged(RuleCondition* child, bool newState, Category category, Variant lcontext = Variant()) = 0;
|
||||
|
||||
virtual void addChild(std::shared_ptr<RuleCondition> child) {
|
||||
if (child) {
|
||||
child->setCompositeParent(this);
|
||||
children.push_back(child);
|
||||
}
|
||||
};
|
||||
|
||||
virtual void enable() {
|
||||
if (!enabled) {
|
||||
for (auto c : children) {
|
||||
c->enable();
|
||||
}
|
||||
enabled = true;
|
||||
}
|
||||
}
|
||||
virtual void disable() {
|
||||
if (enabled) {
|
||||
for (auto c : children) {
|
||||
c->disable();
|
||||
}
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} /* namespace rule */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
#endif /* SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULECONDITION_H_ */
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* hos_ruleengine_service.h
|
||||
*
|
||||
* Created on: 26.04.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_HOS_COSGI_RULEENGINE_HOS_COSGI_SERVICE_RULEENGINE_RULEENGINE_SERVICE_H_
|
||||
#define INCLUDE_HOS_COSGI_RULEENGINE_HOS_COSGI_SERVICE_RULEENGINE_RULEENGINE_SERVICE_H_
|
||||
|
||||
|
||||
#include <hos/cosgi/service/Interface.h>
|
||||
#include <memory>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
|
||||
namespace rule {
|
||||
class RuleCondition;
|
||||
class Rule;
|
||||
}
|
||||
|
||||
class RuleConditionFactory : public virtual interface::Object {
|
||||
public:
|
||||
virtual std::shared_ptr<rule::RuleCondition> createCondition(rule::Rule* parent, ::libvariant::Variant raw) = 0;
|
||||
};
|
||||
|
||||
|
||||
class RuleEngineService : public virtual interface::Service {
|
||||
public:
|
||||
static constexpr const char* SERVICE_NAME = "hos_ruleengine_service";
|
||||
|
||||
virtual void registerRuleConditionFactory(std::string type, std::shared_ptr<RuleConditionFactory> factory) = 0;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ruleengine
|
||||
} // namespace service
|
||||
} // namespace cosgi
|
||||
} // namespace hos
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* INCLUDE_HOS_COSGI_RULEENGINE_HOS_COSGI_SERVICE_RULEENGINE_RULEENGINE_SERVICE_H_ */
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <hos/cosgi/service/Interface.h>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
|
||||
|
||||
// forward declarations
|
||||
namespace devicerepository { class DeviceRepositoryService; }
|
||||
|
||||
|
||||
// main namespace
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
|
||||
|
||||
// Forward declarations
|
||||
namespace conditions {
|
||||
class RuleCondition;
|
||||
enum class ConditionTriggerType : int;
|
||||
}
|
||||
class RulePackage;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Public COSGI interface of a rule.
|
||||
*/
|
||||
class Rule
|
||||
: public virtual interface::Object {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Returns a reference to the parent rule package.
|
||||
*
|
||||
* \return rule package.
|
||||
*/
|
||||
virtual RulePackage* getParent() noexcept = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the name of the rule.
|
||||
*
|
||||
* \return name.
|
||||
*/
|
||||
virtual const std::string& getName() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns whether the rule is currently active.
|
||||
*
|
||||
* Only conditions of trigger type "state" can activate a rule.
|
||||
*
|
||||
* \return whether rule is active.
|
||||
*/
|
||||
virtual bool isActive() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Evaluates the conditions of the rule and may execute associated scripts.
|
||||
*
|
||||
* Only active conditions of trigger type "state" can return true here.
|
||||
*
|
||||
* May return exceptions derived from std::exception.
|
||||
*
|
||||
* \return evaluation result.
|
||||
*/
|
||||
virtual bool evaluate() = 0;
|
||||
|
||||
/**
|
||||
* Executes the associated script.
|
||||
*
|
||||
* May return exceptions derived from std::exception.
|
||||
*
|
||||
* \param[in] local context.
|
||||
*/
|
||||
virtual void executeScript(const libvariant::Variant& lContext = libvariant::Variant()) = 0;
|
||||
|
||||
/**
|
||||
* Executes the associated exit script.
|
||||
*
|
||||
* May return exceptions derived from std::exception.
|
||||
*
|
||||
* \param[in] local context.
|
||||
*/
|
||||
virtual void executeExitScript(const libvariant::Variant& lContext = libvariant::Variant()) = 0;
|
||||
|
||||
/**
|
||||
* Returns whether this rule is enabled.
|
||||
*
|
||||
* \return enabled
|
||||
*/
|
||||
virtual bool isEnabled() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Enable/Disable this rule package.
|
||||
*
|
||||
* \param[in] enabled.
|
||||
*/
|
||||
virtual void setEnabled(bool enabled) noexcept = 0;
|
||||
|
||||
|
||||
/* Interface for third-party conditions. */
|
||||
|
||||
/**
|
||||
* Creates and returns a new condition based on the given json config.
|
||||
*
|
||||
* \param[in] json config.
|
||||
* \return new rule condition.
|
||||
*/
|
||||
virtual std::shared_ptr<conditions::RuleCondition> createRuleCondition(const libvariant::Variant& raw) = 0;
|
||||
|
||||
/**
|
||||
* Indicates that one of the conditions of the rule changed state.
|
||||
*
|
||||
* \param[in] newState new state.
|
||||
* \param[in] trigger trigger type.
|
||||
* \param[in] lcontext local context that should be passed to script.
|
||||
*/
|
||||
virtual void conditionStateChanged(bool newState, const conditions::ConditionTriggerType& trigger,
|
||||
const libvariant::Variant& lcontext = libvariant::Variant()) noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns a reference to the device repository service.
|
||||
*
|
||||
* \return device repository service.
|
||||
*/
|
||||
virtual devicerepository::DeviceRepositoryService* getDeviceRepository() noexcept = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <hos/cosgi/service/Interface.h>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
|
||||
|
||||
// Forward declarations
|
||||
namespace hos { namespace cosgi { namespace service {
|
||||
namespace scripting { class ScriptingService; }
|
||||
namespace scripting { class GlobalScriptContext; }
|
||||
} } }
|
||||
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
|
||||
|
||||
// Forward declarations
|
||||
class RuleEngineService;
|
||||
|
||||
|
||||
// main namespace
|
||||
namespace rules {
|
||||
|
||||
|
||||
// Forward declarations
|
||||
class Rule;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Public COSGI interface of a rule package.
|
||||
*/
|
||||
class RulePackage
|
||||
: public virtual interface::Object {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Returns a reference to the rule engine service.
|
||||
*
|
||||
* \return rule engine service.
|
||||
*/
|
||||
virtual service::ruleengine::RuleEngineService* getParent() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the name of the rule package.
|
||||
*
|
||||
* \return name.
|
||||
*/
|
||||
virtual const std::string& getName() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns an identifier indicating the scripting language.
|
||||
*
|
||||
* \return scripting language identifier.
|
||||
*/
|
||||
virtual const std::string& getLanguage() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the rule with the given name.
|
||||
*
|
||||
* \param[in] name rule name.
|
||||
* \return weak reference to rule (expired reference in case of rule not found).
|
||||
*/
|
||||
virtual std::weak_ptr<Rule> getRule(const std::string& name) noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns all rules contained within the rule package
|
||||
*
|
||||
* \return vector of weak references.
|
||||
*/
|
||||
virtual std::vector<std::weak_ptr<Rule>> getRules() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the number of contained rules.
|
||||
*
|
||||
* \return rule count.
|
||||
*/
|
||||
virtual size_t getRuleCount() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns whether this rule package is enabled.
|
||||
*
|
||||
* \return enabled
|
||||
*/
|
||||
virtual bool isEnabled() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Enable/Disable this rule package.
|
||||
*
|
||||
* \param[in] enabled.
|
||||
*/
|
||||
virtual void setEnabled(bool enabled) noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns a reference to the associated scripting service.
|
||||
*
|
||||
* \return scripting service.
|
||||
*/
|
||||
virtual service::scripting::ScriptingService* getScriptingService() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns a reference to the associated global script context.
|
||||
*
|
||||
* \return global script context.
|
||||
*/
|
||||
virtual std::weak_ptr<scripting::GlobalScriptContext> getGlobalScriptContext() noexcept = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <hos/cosgi/service/Interface.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
|
||||
|
||||
// forward declarations
|
||||
class Rule;
|
||||
|
||||
|
||||
// main namespace
|
||||
namespace conditions {
|
||||
|
||||
|
||||
// forward declarations
|
||||
class RuleCompositeCondition;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Condition trigger type.
|
||||
*
|
||||
* Conditions can have two different trigger types:
|
||||
* - Event trigger: Conditions are triggered by events happening.
|
||||
* - State trigger: Condition are triggered by device state.
|
||||
*
|
||||
* "Both" indicates that an condition has both trigger types.
|
||||
**/
|
||||
enum class ConditionTriggerType : int {
|
||||
Event = 1,
|
||||
State = 2,
|
||||
Both = 3
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Public COSGI interface of a rule condition.
|
||||
*/
|
||||
class RuleCondition
|
||||
: public virtual interface::Object {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Returns the type of the condition.
|
||||
*
|
||||
* \return condition type.
|
||||
*/
|
||||
virtual const std::string& getType() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the trigger type of the condition.
|
||||
*
|
||||
* \return trigger type.
|
||||
*/
|
||||
virtual ConditionTriggerType getTriggerType() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the current state of the condition.
|
||||
*
|
||||
* This function returns a cached value.
|
||||
*
|
||||
* \return current state.
|
||||
*/
|
||||
virtual bool getCurrentState() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Evaluates the condition and returns the result.
|
||||
*
|
||||
* \return evaluation result.
|
||||
*/
|
||||
virtual bool evaluate() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns a reference to the parent rule.
|
||||
*
|
||||
* \return parent rule.
|
||||
*/
|
||||
virtual rules::Rule* getParent() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns whether this rule condition is enabled.
|
||||
*
|
||||
* \return enabled.
|
||||
*/
|
||||
virtual bool isEnabled() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Enable/Disable this rule condition.
|
||||
*
|
||||
* \param[in] enabled.
|
||||
*/
|
||||
virtual void setEnabled(bool enabled) noexcept = 0;
|
||||
|
||||
|
||||
/* Interface for third-party conditions. */
|
||||
|
||||
/**
|
||||
* Sets the composite condition this condition is contained within.
|
||||
*
|
||||
* \param[in] parent composite condition.
|
||||
*/
|
||||
virtual void setCompositeParent(RuleCompositeCondition* compositeParent) noexcept = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Public COSGI interface of a composite condition.
|
||||
*/
|
||||
class RuleCompositeCondition
|
||||
: public virtual RuleCondition {
|
||||
|
||||
public:
|
||||
|
||||
/* Interface for third-party conditions. */
|
||||
|
||||
/**
|
||||
* Indicates that a contained condition has changed its state.
|
||||
*
|
||||
* \param[in] child condition whose state has changed.
|
||||
* \param[in] newState new state.
|
||||
* \param[in] trigger trigger type.
|
||||
* \param[in] lcontext local context that should be passed to the script.
|
||||
*/
|
||||
virtual void childStateChanged( RuleCondition* child,
|
||||
bool newState,
|
||||
ConditionTriggerType trigger,
|
||||
const libvariant::Variant& lcontext = libvariant::Variant() ) noexcept = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Adds a new condition.
|
||||
*
|
||||
* \param[in] child child condition.
|
||||
*/
|
||||
virtual void addChild(std::shared_ptr<RuleCondition> child) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} /* namespace conditions */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "RuleCondition.h"
|
||||
|
||||
|
||||
|
||||
// main namespace
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
namespace conditions {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Base class for condition implementations.
|
||||
*/
|
||||
class RuleConditionImpl
|
||||
: public virtual RuleCondition {
|
||||
|
||||
protected:
|
||||
|
||||
rules::Rule* parent;
|
||||
ConditionTriggerType triggerType;
|
||||
std::string type;
|
||||
|
||||
bool currentState = false;
|
||||
RuleCompositeCondition* compositeParent = nullptr;
|
||||
bool enabled = false;
|
||||
|
||||
void notifyStateChangeToParent(bool newState, ConditionTriggerType category, const libvariant::Variant& lcontext = libvariant::Variant());
|
||||
|
||||
public:
|
||||
|
||||
RuleConditionImpl(rules::Rule* parent, ConditionTriggerType triggerType, const std::string& type) :
|
||||
parent(parent), triggerType(triggerType), type(type) {}
|
||||
|
||||
virtual rules::Rule* getParent() noexcept override {
|
||||
return parent;
|
||||
}
|
||||
|
||||
virtual void setCompositeParent(RuleCompositeCondition* compositeParent) noexcept override {
|
||||
this->compositeParent = compositeParent;
|
||||
}
|
||||
|
||||
virtual const std::string& getType() noexcept override {
|
||||
return type;
|
||||
}
|
||||
|
||||
virtual ConditionTriggerType getTriggerType() noexcept override {
|
||||
return triggerType;
|
||||
}
|
||||
|
||||
virtual bool getCurrentState() noexcept override {
|
||||
return currentState;
|
||||
}
|
||||
|
||||
virtual bool evaluate() noexcept override {
|
||||
return currentState;
|
||||
}
|
||||
|
||||
virtual bool isEnabled() noexcept override {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
virtual void setEnabled(bool enabled) noexcept override {
|
||||
this->enabled;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Base class for composite condition implementations.
|
||||
*/
|
||||
class RuleCompositeConditionImpl
|
||||
: public virtual RuleCompositeCondition,
|
||||
public RuleConditionImpl {
|
||||
|
||||
protected:
|
||||
std::vector<std::shared_ptr<RuleCondition>> children;
|
||||
|
||||
public:
|
||||
|
||||
RuleCompositeConditionImpl(Rule* parent, ConditionTriggerType category, std::string type) :
|
||||
RuleConditionImpl(parent, category, type) {}
|
||||
|
||||
virtual void childStateChanged( RuleCondition* child,
|
||||
bool newState,
|
||||
ConditionTriggerType category,
|
||||
const libvariant::Variant& lcontext = libvariant::Variant() ) noexcept override = 0;
|
||||
|
||||
virtual void addChild(std::shared_ptr<RuleCondition> child) override {
|
||||
if (child) {
|
||||
child->setCompositeParent(this);
|
||||
children.push_back(child);
|
||||
}
|
||||
};
|
||||
|
||||
virtual void setEnabled(bool enabled) noexcept override {
|
||||
if (this->enabled != enabled) {
|
||||
for (auto c : children) {
|
||||
c->setEnabled(enabled);
|
||||
}
|
||||
this->enabled = enabled;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} /* namespace conditions */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ extern "C" {
|
||||
}
|
||||
|
||||
#include <hos/cosgi/service/core/CoreService.h>
|
||||
#include "hos/cosgi/service/ruleengine/ruleengine_serviceimpl.h"
|
||||
#include "hos/cosgi/service/ruleengine/RuleEngineServiceImpl.h"
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
+29
-14
@@ -5,7 +5,6 @@
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#include "ruleengine_serviceimpl.h"
|
||||
#include <ros/ros.h>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
@@ -16,8 +15,12 @@
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
#include "rule/RulePackage.h"
|
||||
#include "rule/RuleConditionImpl.h"
|
||||
#include "RuleEngineServiceImpl.h"
|
||||
|
||||
#include "rules/conditions/LogicalAndCondition.h"
|
||||
#include "rules/conditions/LogicalOrCondition.h"
|
||||
#include "rules/conditions/DeviceMsgCondition.h"
|
||||
#include "rules/RulePackageImpl.h"
|
||||
|
||||
|
||||
namespace hos {
|
||||
@@ -62,11 +65,11 @@ void RuleEngineServiceImpl::init() {
|
||||
XmlRpc::XmlRpcValue rawValue;
|
||||
nodehandle->getParam(ruleEnginePrefix, rawValue);
|
||||
schemaLoader.reset(new utils::SchemaLoader());
|
||||
registerRuleConditionFactory("logical_or", std::make_shared<rule::LogicalOrConditionFactory>());
|
||||
registerRuleConditionFactory("logical_and", std::make_shared<rule::LogicalAndConditionFactory>());
|
||||
registerRuleConditionFactory("devicestatusmsg", std::make_shared<rule::DeviceStatusMsgConditionFactory>());
|
||||
registerRuleConditionFactory("devicecommandmsg", std::make_shared<rule::DeviceCommandMsgConditionFactory>());
|
||||
registerRuleConditionFactory("devicestatechange", std::make_shared<rule::DeviceStateChangeConditionFactory>());
|
||||
registerRuleConditionFactory("logical_or", std::make_shared<rules::conditions::LogicalOrConditionFactory>());
|
||||
registerRuleConditionFactory("logical_and", std::make_shared<rules::conditions::LogicalAndConditionFactory>());
|
||||
registerRuleConditionFactory("devicestatusmsg", std::make_shared<rules::conditions::DeviceStatusMsgConditionFactory>());
|
||||
registerRuleConditionFactory("devicecommandmsg", std::make_shared<rules::conditions::DeviceCommandMsgConditionFactory>());
|
||||
registerRuleConditionFactory("devicestatechange", std::make_shared<rules::conditions::DeviceStateChangeConditionFactory>());
|
||||
if (rawValue.getType() == XmlRpc::XmlRpcValue::TypeStruct) {
|
||||
for (auto pkg : rawValue) {
|
||||
std::string pname = pkg.first;
|
||||
@@ -96,11 +99,11 @@ void RuleEngineServiceImpl::addRulePkg(std::string name, std::string rawValue) {
|
||||
Variant m = Deserialize(rawValue, SERIALIZE_JSON);
|
||||
SchemaResult sr = SchemaValidate(s, m, schemaLoader.get());
|
||||
if (!sr.Error()) {
|
||||
std::shared_ptr<rule::RulePackage> pkg = rule::RulePackage::createRulePackage(this, name, m);
|
||||
std::shared_ptr<rules::RulePackageImpl> pkg = rules::RulePackageImpl::createRulePackage(this, name, m);
|
||||
if (pkg) {
|
||||
if (pkg->getScriptingService()) {
|
||||
rulePkgs.insert({name, pkg});
|
||||
pkg->enable();
|
||||
pkg->setEnabled(true);
|
||||
} else {
|
||||
noExecRulePkgs.insert({name, pkg});
|
||||
std::cout << "No execution service found for rule package \"" << name << "\"" << std::endl;
|
||||
@@ -142,17 +145,17 @@ scripting::ScriptingService* RuleEngineServiceImpl::getExecutionBackend(std::str
|
||||
}
|
||||
|
||||
|
||||
void RuleEngineServiceImpl::registerRuleConditionFactory(std::string type, std::shared_ptr<RuleConditionFactory> factory) {
|
||||
void RuleEngineServiceImpl::registerRuleConditionFactory(const std::string& type, std::shared_ptr<RuleConditionFactory> factory) noexcept {
|
||||
condFactories.insert({type, factory});
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<rule::RulePackage> RuleEngineServiceImpl::getRulePackage(const std::string& name) {
|
||||
std::shared_ptr<rule::RulePackage> retval;
|
||||
std::weak_ptr<rules::RulePackage> RuleEngineServiceImpl::getRulePackage(const std::string& name) noexcept {
|
||||
std::weak_ptr<rules::RulePackage> retval;
|
||||
try {
|
||||
retval = rulePkgs.at(name);
|
||||
} catch(...) {}
|
||||
if (!retval) {
|
||||
if (retval.expired()) {
|
||||
try {
|
||||
retval = noExecRulePkgs.at(name);
|
||||
} catch(...) {}
|
||||
@@ -160,6 +163,18 @@ std::shared_ptr<rule::RulePackage> RuleEngineServiceImpl::getRulePackage(const s
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::weak_ptr<rules::RulePackage>> RuleEngineServiceImpl::getRulePackages() noexcept {
|
||||
|
||||
}
|
||||
|
||||
|
||||
size_t RuleEngineServiceImpl::getRulePackageCount() noexcept {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace ruleengine
|
||||
} // namespace service
|
||||
} // namespace cosgi
|
||||
+33
-24
@@ -1,12 +1,7 @@
|
||||
/*
|
||||
* hos_ruleengine_service_impl.h
|
||||
*
|
||||
* Created on: 26.04.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_HOS_COSGI_RULEENGINE_HOS_RULEENGINE_SERVICE_IMPL_H_
|
||||
#define INCLUDE_HOS_COSGI_RULEENGINE_HOS_RULEENGINE_SERVICE_IMPL_H_
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
@@ -15,10 +10,10 @@
|
||||
#include <hos_core_msgs/DeviceStatusUpdate.h>
|
||||
#include <hos_core_msgs/HosStatusUpdate.h>
|
||||
#include <hos/utils/SchemaLoader.h>
|
||||
#include <hos/cosgi/service/ruleengine/ruleengine_service.h>
|
||||
#include <hos/cosgi/service/scripting/scripting_service.h>
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include <hos/cosgi/service/Implementation.h>
|
||||
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||
#include <hos/cosgi/service/scripting/ScriptingService.h>
|
||||
#include <ros/ros.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -45,18 +40,19 @@ namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rule {
|
||||
|
||||
class RulePackage;
|
||||
namespace rules {
|
||||
class RulePackageImpl;
|
||||
}
|
||||
|
||||
|
||||
class RuleEngineServiceImpl;
|
||||
|
||||
class RuleEngineServiceImpl :
|
||||
public virtual RuleEngineService,
|
||||
public virtual implementation::Service<RuleEngineServiceImpl> {
|
||||
|
||||
private:
|
||||
typedef std::map<std::string, std::shared_ptr<rule::RulePackage>> rulePkgMap_t;
|
||||
typedef std::map<std::string, std::shared_ptr<rules::RulePackageImpl>> rulePkgMap_t;
|
||||
typedef std::map<std::string, scripting::ScriptingService*> execServiceMap_t;
|
||||
typedef std::map<std::string, std::shared_ptr<RuleConditionFactory>> condFactoryMap_t;
|
||||
|
||||
@@ -82,39 +78,52 @@ private:
|
||||
void init();
|
||||
|
||||
public:
|
||||
|
||||
/* Initialization */
|
||||
|
||||
void setCoreService(service::core::CoreService* coreService);
|
||||
|
||||
void setRepoService(devicerepository::DeviceRepositoryService* repoService);
|
||||
|
||||
|
||||
/* Public Service Implementations */
|
||||
|
||||
virtual void registerRuleConditionFactory(std::string type, std::shared_ptr<RuleConditionFactory> factory) override;
|
||||
virtual void registerRuleConditionFactory(const std::string& type, std::shared_ptr<RuleConditionFactory> factory) noexcept override;
|
||||
|
||||
virtual std::weak_ptr<rules::RulePackage> getRulePackage(const std::string& name) noexcept override;
|
||||
|
||||
virtual std::vector<std::weak_ptr<rules::RulePackage>> getRulePackages() noexcept override;
|
||||
|
||||
|
||||
virtual size_t getRulePackageCount() noexcept override;
|
||||
|
||||
|
||||
/* Internal Stuff */
|
||||
|
||||
bool isInitialized() { return initialized; }
|
||||
|
||||
void addExecutionBackend(scripting::ScriptingService* service);
|
||||
|
||||
scripting::ScriptingService* getExecutionBackend(std::string language);
|
||||
|
||||
std::shared_ptr<RuleConditionFactory> getRuleConditionFactory(std::string type) { return condFactories[type]; }
|
||||
std::shared_ptr<RuleConditionFactory> getRuleConditionFactory(std::string type) {
|
||||
return condFactories[type];
|
||||
}
|
||||
|
||||
utils::SchemaLoader* getHOSSchemaLoader() { return schemaLoader.get(); }
|
||||
utils::SchemaLoader* getHOSSchemaLoader() {
|
||||
return schemaLoader.get();
|
||||
}
|
||||
|
||||
devicerepository::DeviceRepositoryService* getDeviceRepository() { return repoService; }
|
||||
devicerepository::DeviceRepositoryService* getDeviceRepository() {
|
||||
return repoService;
|
||||
}
|
||||
|
||||
std::shared_ptr<rule::RulePackage> getRulePackage(const std::string& name);
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace ruleengine
|
||||
} // namespace service
|
||||
} // namespace cosgi
|
||||
} // namespace hos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* INCLUDE_HOS_COSGI_RULEENGINE_HOS_RULEENGINE_SERVICE_IMPL_H_ */
|
||||
@@ -1,432 +0,0 @@
|
||||
/*
|
||||
* RuleCondition.cpp
|
||||
*
|
||||
* Created on: 29.04.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#include "RuleConditionImpl.h"
|
||||
#include <hos/cosgi/service/ruleengine/rule/Rule.h>
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include <ros/ros.h>
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rule {
|
||||
|
||||
|
||||
std::shared_ptr<rule::RuleCondition> LogicalOrConditionFactory::createCondition(rule::Rule* parent, Variant raw) {
|
||||
std::shared_ptr<rule::LogicalOrCondition> retval;
|
||||
if (raw.HasPath("conditions") && raw["conditions"].IsList() && raw["conditions"].Size() > 0) {
|
||||
retval = std::make_shared<rule::LogicalOrCondition>(parent);
|
||||
for (auto c : raw["conditions"].AsList()) {
|
||||
auto cond = parent->createRuleCondition(c);
|
||||
if (cond) {
|
||||
retval->addChild(cond);
|
||||
} else {
|
||||
throw std::runtime_error("Could not create condition.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property condition or is not a list.");
|
||||
}
|
||||
return std::static_pointer_cast<rule::RuleCondition>(retval);
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<rule::RuleCondition> LogicalAndConditionFactory::createCondition(rule::Rule* parent, Variant raw) {
|
||||
std::shared_ptr<rule::LogicalAndCondition> retval;
|
||||
if (raw.HasPath("conditions") && raw["conditions"].IsList() && raw["conditions"].Size() > 0) {
|
||||
retval = std::make_shared<rule::LogicalAndCondition>(parent);
|
||||
for (auto c : raw["conditions"].AsList()) {
|
||||
auto cond = parent->createRuleCondition(c);
|
||||
if (cond) {
|
||||
retval->addChild(cond);
|
||||
} else {
|
||||
throw std::runtime_error("Could not create condition.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property condition or is not a list.");
|
||||
}
|
||||
return std::static_pointer_cast<rule::RuleCondition>(retval);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RuleCondition::notifyStateChangeToParent(bool newState, Category category, Variant lcontext) {
|
||||
if (compositeParent) {
|
||||
compositeParent->childStateChanged(this, newState, category, lcontext);
|
||||
} else {
|
||||
parent->conditionStateChanged(newState, category, lcontext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LogicalOrCondition::addChild(std::shared_ptr<RuleCondition> child) {
|
||||
if (child->getCategory() == Category::Event) {
|
||||
eventChildrenCount++;
|
||||
} else if (child->getCategory() == Category::State) {
|
||||
stateChildrenCount++;
|
||||
} else {
|
||||
mixedChildrenCount++;
|
||||
}
|
||||
if (mixedChildrenCount > 0 || (eventChildrenCount > 0 && stateChildrenCount > 0)) {
|
||||
category = Category::Mixed;
|
||||
} else if (eventChildrenCount > 0 && stateChildrenCount == 0) {
|
||||
category = Category::Event;
|
||||
} else {
|
||||
category = Category::State;
|
||||
}
|
||||
RuleCompositeCondition::addChild(child);
|
||||
}
|
||||
|
||||
|
||||
void LogicalOrCondition::childStateChanged(RuleCondition* child, bool newState, Category category, Variant lcontext) {
|
||||
if (newState && category == Category::Event && !currentState) {
|
||||
notifyStateChangeToParent(true, category, lcontext);
|
||||
} else if (category == Category::State) {
|
||||
if (newState) {
|
||||
trueChildrenCount++;
|
||||
if (!currentState) {
|
||||
currentState = true;
|
||||
notifyStateChangeToParent(true, category, lcontext);
|
||||
}
|
||||
} else {
|
||||
trueChildrenCount--;
|
||||
if (currentState && trueChildrenCount <= 0) {
|
||||
currentState = false;
|
||||
notifyStateChangeToParent(false, category, lcontext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LogicalOrCondition::evaluate() {
|
||||
// Event conditions always evaluate to false
|
||||
if (category == Category::Event) {
|
||||
return false;
|
||||
}
|
||||
trueChildrenCount = 0;
|
||||
for (auto c : children) {
|
||||
if (c->evaluate()) {
|
||||
trueChildrenCount++;
|
||||
}
|
||||
}
|
||||
currentState = trueChildrenCount > 0;
|
||||
return currentState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LogicalAndCondition::addChild(std::shared_ptr<RuleCondition> child) {
|
||||
if (child->getCategory() == Category::Event) {
|
||||
if (eventChildrenCount > 0) {
|
||||
throw new std::runtime_error("Cannot have an and condition with more than two event conditions.");
|
||||
}
|
||||
eventChildrenCount++;
|
||||
} else if (child->getCategory() == Category::State) {
|
||||
stateChildrenCount++;
|
||||
} else {
|
||||
mixedChildrenCount++;
|
||||
}
|
||||
if (mixedChildrenCount > 0 || (eventChildrenCount > 0 && stateChildrenCount > 0)) {
|
||||
category = Category::Mixed;
|
||||
} else if (eventChildrenCount > 0 && stateChildrenCount == 0) {
|
||||
category = Category::Event;
|
||||
} else {
|
||||
category = Category::State;
|
||||
}
|
||||
RuleCompositeCondition::addChild(child);
|
||||
}
|
||||
|
||||
void LogicalAndCondition::childStateChanged(RuleCondition* child, bool newState, Category category, Variant lcontext) {
|
||||
if (newState && category == Category::Event && !currentState && trueChildrenCount >= children.size()-1) {
|
||||
notifyStateChangeToParent(true, category);
|
||||
} else if (category == Category::State) {
|
||||
if (newState) {
|
||||
trueChildrenCount++;
|
||||
if (!currentState && trueChildrenCount >= children.size()) {
|
||||
currentState = true;
|
||||
notifyStateChangeToParent(true, category, lcontext);
|
||||
}
|
||||
} else {
|
||||
trueChildrenCount--;
|
||||
if (currentState) {
|
||||
currentState = false;
|
||||
notifyStateChangeToParent(false, category, lcontext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool LogicalAndCondition::evaluate() {
|
||||
// Event conditions always evaluate to false
|
||||
if (category == Category::Event) {
|
||||
return false;
|
||||
}
|
||||
trueChildrenCount = 0;
|
||||
for (auto c : children) {
|
||||
if (c->evaluate()) {
|
||||
trueChildrenCount++;
|
||||
}
|
||||
}
|
||||
currentState = trueChildrenCount == children.size();
|
||||
return currentState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DeviceMsgCondition::notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||
switch (key) {
|
||||
case devicerepository::DeviceEvent::EventType::DEVICE_ADDED:
|
||||
if (!device && this->deviceID.compare(e->device->getDeviceID()) == 0) {
|
||||
ROS_INFO_STREAM("Rule " << parent->name << ": Device " << deviceID << " appeared.");
|
||||
device = e->device;
|
||||
parent->getDeviceRepository()->deleteObserver(devicerepository::DeviceEvent::EventType::DEVICE_ADDED, this);
|
||||
_registerAsListener();
|
||||
}
|
||||
break;
|
||||
case devicerepository::DeviceEvent::EventType::DEVICE_REMOVED:
|
||||
if (device && device->getDeviceID().compare(e->device->getDeviceID()) == 0) {
|
||||
ROS_ERROR_STREAM("Rule " << parent->name << ": Device " << deviceID << " disappeared.");
|
||||
device->deleteObserver(this);
|
||||
device = nullptr;
|
||||
parent->getDeviceRepository()->addObserver(devicerepository::DeviceEvent::EventType::DEVICE_ADDED, this);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceMsgCondition::enable() {
|
||||
auto repoService = parent->getDeviceRepository();
|
||||
auto device = repoService->getDevice(deviceID);
|
||||
if (!device.expired()) {
|
||||
this->device = device.lock().get();
|
||||
_registerAsListener();
|
||||
} else {
|
||||
ROS_ERROR_STREAM("Rule " << parent->name << ": Could not find device " << deviceID);
|
||||
parent->getDeviceRepository()->addObserver(devicerepository::DeviceEvent::EventType::DEVICE_ADDED, this);
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceMsgCondition::disable() {
|
||||
if (device) {
|
||||
device->deleteObserver(this);
|
||||
device = nullptr;
|
||||
}
|
||||
parent->getDeviceRepository()->deleteObserver(this);
|
||||
}
|
||||
|
||||
void DeviceMsgCondition::_registerAsListener() {
|
||||
if (device) {
|
||||
for (auto k : _listenerKeys) {
|
||||
device->addObserver(k, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
std::shared_ptr<rule::RuleCondition> DeviceStatusMsgConditionFactory::createCondition(rule::Rule* parent, Variant raw) {
|
||||
std::shared_ptr<rule::DeviceStatusMsgCondition> retval;
|
||||
std::string deviceID;
|
||||
if (raw.HasPath("deviceid") && raw["deviceid"].IsString()) {
|
||||
deviceID = raw["deviceid"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property deviceid or is not an string.");
|
||||
}
|
||||
std::string msgPointer;
|
||||
if (raw.HasPath("msgpointer")) {
|
||||
if (raw["msgpointer"].IsString()) {
|
||||
msgPointer = raw["msgpointer"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
||||
}
|
||||
}
|
||||
Variant msgValue;
|
||||
if (raw.HasPath("msgvalue")) {
|
||||
msgValue = raw["msgvalue"];
|
||||
}
|
||||
retval = std::make_shared<rule::DeviceStatusMsgCondition>(parent, deviceID, msgPointer, msgValue);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void DeviceStatusMsgCondition::notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||
switch (e->eventType) {
|
||||
case devicerepository::DeviceEvent::EventType::STATUS_UPDATE_RECEIVED:
|
||||
if (device && device == e->device) {
|
||||
auto e2 = static_cast<const devicerepository::DeviceStatusMsgEvent*>(e);
|
||||
bool notify = true;
|
||||
Variant value;
|
||||
if (msgPointer.empty()) {
|
||||
value = e2->statusMsg;
|
||||
} else if (e2->statusMsg.HasPath(msgPointer)) {
|
||||
value = e2->statusMsg.GetPath(msgPointer);
|
||||
} else {
|
||||
notify = false;
|
||||
}
|
||||
if (notify && !msgValue.IsNull()) {
|
||||
if (msgValue != value) {
|
||||
notify = false;
|
||||
}
|
||||
}
|
||||
if (notify) {
|
||||
Variant lcontext;
|
||||
lcontext["event_deviceid"] = Variant(e->device->getDeviceID());
|
||||
lcontext["event_type"] = Variant("statusmsg");
|
||||
lcontext["event_msg"] = e2->statusMsg;
|
||||
notifyStateChangeToParent(true, Category::Event, lcontext);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DeviceMsgCondition::notificationReceived(o, key, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<rule::RuleCondition> DeviceCommandMsgConditionFactory::createCondition(rule::Rule* parent, Variant raw) {
|
||||
std::shared_ptr<rule::DeviceCommandMsgCondition> retval;
|
||||
std::string deviceID;
|
||||
if (raw.HasPath("deviceid") && raw["deviceid"].IsString()) {
|
||||
deviceID = raw["deviceid"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property deviceid or is not an string.");
|
||||
}
|
||||
std::string msgPointer;
|
||||
if (raw.HasPath("msgpointer")) {
|
||||
if (raw["msgpointer"].IsString()) {
|
||||
msgPointer = raw["msgpointer"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
||||
}
|
||||
}
|
||||
Variant msgValue;
|
||||
if (raw.HasPath("msgvalue")) {
|
||||
msgValue = raw["msgvalue"];
|
||||
}
|
||||
retval = std::make_shared<rule::DeviceCommandMsgCondition>(parent, deviceID, msgPointer, msgValue);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void DeviceCommandMsgCondition::notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||
switch (e->eventType) {
|
||||
case devicerepository::DeviceEvent::EventType::COMMAND_RECEIVED:
|
||||
if (device && device == e->device) {
|
||||
auto e2 = static_cast<const devicerepository::DeviceCmdMsgEvent*>(e);
|
||||
bool notify = true;
|
||||
Variant value;
|
||||
if (msgPointer.empty()) {
|
||||
value = e2->cmdMsg;
|
||||
} else if (e2->cmdMsg.HasPath(msgPointer)) {
|
||||
value = e2->cmdMsg.GetPath(msgPointer);
|
||||
} else {
|
||||
notify = false;
|
||||
}
|
||||
if (notify && !msgValue.IsNull()) {
|
||||
if (msgValue != value) {
|
||||
notify = false;
|
||||
}
|
||||
}
|
||||
if (notify) {
|
||||
Variant lcontext;
|
||||
lcontext["event_deviceid"] = Variant(e->device->getDeviceID());
|
||||
lcontext["event_type"] = Variant("commandmsg");
|
||||
lcontext["event_msg"] = e2->cmdMsg;
|
||||
notifyStateChangeToParent(true, Category::Event, lcontext);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DeviceMsgCondition::notificationReceived(o, key, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<rule::RuleCondition> DeviceStateChangeConditionFactory::createCondition(rule::Rule* parent, Variant raw) {
|
||||
std::shared_ptr<rule::DeviceStateChangeCondition> retval;
|
||||
std::string deviceID;
|
||||
if (raw.HasPath("deviceid") && raw["deviceid"].IsString()) {
|
||||
deviceID = raw["deviceid"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property deviceid or is not an string.");
|
||||
}
|
||||
std::string statePointer;
|
||||
if (raw.HasPath("msgpointer")) {
|
||||
if (raw["msgpointer"].IsString()) {
|
||||
statePointer = raw["msgpointer"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
||||
}
|
||||
}
|
||||
Variant fromValue;
|
||||
if (raw.HasPath("fromvalue")) {
|
||||
fromValue = raw["fromvalue"];
|
||||
}
|
||||
Variant toValue;
|
||||
if (raw.HasPath("tovalue")) {
|
||||
toValue = raw["tovalue"];
|
||||
}
|
||||
retval = std::make_shared<DeviceStateChangeCondition>(parent, deviceID, statePointer, fromValue, toValue);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
void DeviceStateChangeCondition::notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||
switch (e->eventType) {
|
||||
case devicerepository::DeviceEvent::EventType::STATE_CHANGED:
|
||||
if (device && device == e->device) {
|
||||
auto e2 = static_cast<const devicerepository::DeviceStatusMsgEvent*>(e);
|
||||
bool notify = true;
|
||||
Variant current, last;
|
||||
if (msgPointer.empty()) {
|
||||
current = device->getCurrentState();
|
||||
last = device->getLastState();
|
||||
} else if (device->getCurrentState().HasPath(msgPointer) && device->getLastState().HasPath(msgPointer)) {
|
||||
current = device->getCurrentState().GetPath(msgPointer);
|
||||
last = device->getLastState().GetPath(msgPointer);
|
||||
} else {
|
||||
notify = false;
|
||||
}
|
||||
if (notify) {
|
||||
if (current == last) {
|
||||
notify = false;
|
||||
} else if (!fromValue.IsNull() && fromValue != last) {
|
||||
notify = false;
|
||||
} else if (!msgValue.IsNull() && msgValue != current) {
|
||||
notify = false;
|
||||
}
|
||||
}
|
||||
if (notify) {
|
||||
Variant lcontext;
|
||||
lcontext["event_deviceid"] = Variant(e->device->getDeviceID());
|
||||
lcontext["event_type"] = Variant("statechange");
|
||||
lcontext["event_msg"] = e2->statusMsg;
|
||||
notifyStateChangeToParent(true, Category::Event, lcontext);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DeviceMsgCondition::notificationReceived(o, key, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} /* namespace rule */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* RuleConditionImpl.h
|
||||
*
|
||||
* Created on: 11.05.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#ifndef SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULECONDITIONIMPL_H_
|
||||
#define SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULECONDITIONIMPL_H_
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rule/RuleCondition.h>
|
||||
#include <hos/cosgi/service/ruleengine/ruleengine_service.h>
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include <set>
|
||||
|
||||
|
||||
// Service Namespace
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rule {
|
||||
|
||||
using namespace ::libvariant;
|
||||
|
||||
|
||||
class LogicalOrCondition : public RuleCompositeCondition {
|
||||
protected:
|
||||
unsigned eventChildrenCount = 0;
|
||||
unsigned stateChildrenCount = 0;
|
||||
unsigned mixedChildrenCount = 0;
|
||||
unsigned trueChildrenCount = 0;
|
||||
public:
|
||||
LogicalOrCondition(Rule* parent) :
|
||||
RuleCompositeCondition(parent, Category::Mixed, "logical_or") {}
|
||||
|
||||
virtual void addChild(std::shared_ptr<RuleCondition> child) override;
|
||||
virtual void childStateChanged(RuleCondition* child, bool newState, Category category, Variant lcontext = Variant()) override;
|
||||
virtual bool evaluate() override;
|
||||
};
|
||||
|
||||
class LogicalOrConditionFactory : public virtual RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<rule::RuleCondition> createCondition(rule::Rule* parent, ::libvariant::Variant raw) override;
|
||||
};
|
||||
|
||||
|
||||
class LogicalAndCondition : public RuleCompositeCondition {
|
||||
protected:
|
||||
unsigned eventChildrenCount = 0;
|
||||
unsigned stateChildrenCount = 0;
|
||||
unsigned mixedChildrenCount = 0;
|
||||
unsigned trueChildrenCount = 0;
|
||||
public:
|
||||
LogicalAndCondition(Rule* parent) :
|
||||
RuleCompositeCondition(parent, Category::Mixed, "logical_and") {}
|
||||
|
||||
virtual void addChild(std::shared_ptr<RuleCondition> child) override;
|
||||
virtual void childStateChanged(RuleCondition* child, bool newState, Category category, Variant lcontext = Variant()) override;
|
||||
virtual bool evaluate() override;
|
||||
};
|
||||
|
||||
class LogicalAndConditionFactory : public virtual RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<rule::RuleCondition> createCondition(rule::Rule* parent, ::libvariant::Variant raw) override;
|
||||
};
|
||||
|
||||
|
||||
class DeviceMsgCondition : public RuleCondition, public virtual interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent> {
|
||||
protected:
|
||||
const std::string deviceID;
|
||||
devicerepository::Device* device = nullptr;
|
||||
const std::string msgPointer;
|
||||
const Variant msgValue;
|
||||
std::set<devicerepository::DeviceEvent::EventType> _listenerKeys;
|
||||
|
||||
virtual void _registerAsListener();
|
||||
|
||||
public:
|
||||
DeviceMsgCondition(Rule* parent, Category category, std::string type, const std::string deviceID, const std::string msgPointer, const Variant msgValue, std::set<devicerepository::DeviceEvent::EventType> _listenerKeys) :
|
||||
RuleCondition(parent, category, type), deviceID(deviceID), msgPointer(msgPointer), msgValue(msgValue), _listenerKeys(_listenerKeys) {}
|
||||
|
||||
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept override;
|
||||
virtual void enable() override;
|
||||
virtual void disable() override;
|
||||
};
|
||||
|
||||
|
||||
class DeviceStatusMsgCondition : public DeviceMsgCondition {
|
||||
public:
|
||||
DeviceStatusMsgCondition(Rule* parent, const std::string deviceID, const std::string msgPointer, const Variant msgValue) :
|
||||
DeviceMsgCondition(parent, Category::Event, "devicestatusmsg", deviceID, msgPointer, msgValue, {devicerepository::DeviceEvent::EventType::STATUS_UPDATE_RECEIVED}) {}
|
||||
|
||||
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept override;
|
||||
};
|
||||
|
||||
class DeviceStatusMsgConditionFactory : public virtual RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<rule::RuleCondition> createCondition(rule::Rule* parent, Variant raw) override;
|
||||
};
|
||||
|
||||
|
||||
class DeviceCommandMsgCondition : public DeviceMsgCondition {
|
||||
public:
|
||||
DeviceCommandMsgCondition(Rule* parent, const std::string deviceID, const std::string msgPointer, const Variant msgValue) :
|
||||
DeviceMsgCondition(parent, Category::Event, "devicecommandmsg", deviceID, msgPointer, msgValue, {devicerepository::DeviceEvent::EventType::COMMAND_RECEIVED}) {}
|
||||
|
||||
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept override;
|
||||
};
|
||||
|
||||
class DeviceCommandMsgConditionFactory : public virtual RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<rule::RuleCondition> createCondition(rule::Rule* parent, ::libvariant::Variant raw) override;
|
||||
};
|
||||
|
||||
|
||||
class DeviceStateChangeCondition : public DeviceMsgCondition {
|
||||
protected:
|
||||
const Variant fromValue;
|
||||
public:
|
||||
DeviceStateChangeCondition(Rule* parent, const std::string deviceID, const std::string statePointer, const Variant fromValue, const Variant toValue) :
|
||||
DeviceMsgCondition(parent, Category::Event, "devicestatechange", deviceID, statePointer, toValue, {devicerepository::DeviceEvent::EventType::STATE_CHANGED}), fromValue(fromValue) {}
|
||||
|
||||
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept override;
|
||||
};
|
||||
|
||||
class DeviceStateChangeConditionFactory : public virtual RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<rule::RuleCondition> createCondition(rule::Rule* parent, Variant raw) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} /* namespace rule */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
|
||||
#endif /* SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULECONDITIONIMPL_H_ */
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* RulePackage.h
|
||||
*
|
||||
* Created on: 29.04.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#ifndef SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULEPACKAGE_H_
|
||||
#define SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULEPACKAGE_H_
|
||||
|
||||
|
||||
#include <hos/cosgi/service/scripting/scripting_service.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
|
||||
// Forward declarations
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
class RuleEngineServiceImpl;
|
||||
class RuleConditionFactory;
|
||||
namespace rule {
|
||||
class Rule;
|
||||
}
|
||||
}
|
||||
namespace scripting {
|
||||
class GlobalScriptContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rule {
|
||||
|
||||
using namespace ::libvariant;
|
||||
|
||||
class RulePackage {
|
||||
private:
|
||||
typedef std::map<std::string, std::shared_ptr<Rule>> ruleMap_t;
|
||||
|
||||
service::scripting::ScriptingService* executionService = nullptr;
|
||||
std::shared_ptr<scripting::GlobalScriptContext> globalContext;
|
||||
ruleMap_t rules;
|
||||
Variant rawValue;
|
||||
bool enabled = false;
|
||||
|
||||
|
||||
public:
|
||||
service::ruleengine::RuleEngineServiceImpl* const parent;
|
||||
const std::string name;
|
||||
const std::string language;
|
||||
|
||||
static std::shared_ptr<RulePackage> createRulePackage(service::ruleengine::RuleEngineServiceImpl* parent, std::string name, Variant raw);
|
||||
RulePackage(service::ruleengine::RuleEngineServiceImpl* parent, const std::string name, const std::string language, Variant raw);
|
||||
virtual ~RulePackage();
|
||||
|
||||
std::shared_ptr<Rule> getRule(const std::string& name);
|
||||
size_t getRules(std::vector<std::shared_ptr<Rule>>& rules);
|
||||
|
||||
bool isEnabled() { return enabled; }
|
||||
void enable();
|
||||
void disable();
|
||||
|
||||
service::scripting::ScriptingService* getScriptingService() { return executionService; }
|
||||
std::shared_ptr<scripting::GlobalScriptContext> getGlobalScriptContext() { return globalContext; }
|
||||
std::shared_ptr<service::ruleengine::RuleConditionFactory> getConditionFactory(std::string type);
|
||||
};
|
||||
|
||||
} /* namespace rule */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
#endif /* SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULEPACKAGE_H_ */
|
||||
+36
-48
@@ -6,39 +6,36 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rule/Rule.h>
|
||||
#include "../rules/RuleImpl.h"
|
||||
|
||||
#include <hos/cosgi/service/scripting/scripting_service.h>
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rule/RuleCondition.h>
|
||||
#include <ros/ros.h>
|
||||
#include "RulePackage.h"
|
||||
#include <hos/cosgi/service/ruleengine/ruleengine_service.h>
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleCondition.h>
|
||||
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||
#include <hos/cosgi/service/scripting/ScriptingService.h>
|
||||
#include <hos/utils/SchemaLoader.h>
|
||||
#include "../ruleengine_serviceimpl.h"
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
#include "../rules/RulePackageImpl.h"
|
||||
|
||||
#include "../RuleEngineServiceImpl.h"
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rule {
|
||||
namespace rules {
|
||||
|
||||
|
||||
Rule::Rule(RulePackage* parent, std::string name)
|
||||
RuleImpl::RuleImpl(RulePackageImpl* parent, std::string name)
|
||||
: parent(parent), name(name) {}
|
||||
|
||||
|
||||
utils::SchemaLoader* Rule::getHOSSchemaLoader() {
|
||||
return parent->parent->getHOSSchemaLoader();
|
||||
}
|
||||
|
||||
std::shared_ptr<RuleCondition> Rule::createRuleCondition(Variant condition) {
|
||||
std::shared_ptr<RuleCondition> retval;
|
||||
std::shared_ptr<conditions::RuleCondition> RuleImpl::createRuleCondition(const Variant& condition) {
|
||||
std::shared_ptr<conditions::RuleCondition> retval;
|
||||
if (condition.IsMap() && condition.HasPath("type") && condition["type"].IsString()) {
|
||||
if (condition.HasPath("$schema")) {
|
||||
SchemaResult sr = SchemaValidate(Variant(), condition, getHOSSchemaLoader());
|
||||
SchemaResult sr = SchemaValidate(Variant(), condition, parent->parent->getHOSSchemaLoader());
|
||||
if (sr.Error()) {
|
||||
throw std::runtime_error(sr.PrettyPrintMessage());
|
||||
}
|
||||
@@ -60,13 +57,13 @@ std::shared_ptr<RuleCondition> Rule::createRuleCondition(Variant condition) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::shared_ptr<Rule> Rule::createRule(RulePackage* parent, std::string name, Variant raw) {
|
||||
std::shared_ptr<Rule> retval;
|
||||
if (parent->getRule(name)) {
|
||||
std::shared_ptr<RuleImpl> RuleImpl::createRule(RulePackageImpl* parent, std::string name, Variant raw) {
|
||||
std::shared_ptr<RuleImpl> retval;
|
||||
if (!parent->getRule(name).expired()) {
|
||||
throw std::runtime_error("Rule with the same name already exists.");
|
||||
}
|
||||
if (raw.IsMap()) {
|
||||
retval = std::make_shared<Rule>(parent, name);
|
||||
retval = std::make_shared<RuleImpl>(parent, name);
|
||||
if (raw.HasPath("condition") && raw["condition"].IsMap()) {
|
||||
auto condition = raw["condition"];
|
||||
auto cond = retval->createRuleCondition(condition);
|
||||
@@ -78,7 +75,7 @@ std::shared_ptr<Rule> Rule::createRule(RulePackage* parent, std::string name, Va
|
||||
auto scriptFactory = parent->getScriptingService();
|
||||
//ToDo: Create Condition
|
||||
if (raw.HasPath("script") && raw["script"].IsMap()) {
|
||||
auto script = scriptFactory->createScript(parent->getGlobalScriptContext().get(), raw["script"]);
|
||||
auto script = scriptFactory->createScript(raw["script"]);
|
||||
if (script) {
|
||||
retval->script = script;
|
||||
} else {
|
||||
@@ -88,7 +85,7 @@ std::shared_ptr<Rule> Rule::createRule(RulePackage* parent, std::string name, Va
|
||||
throw std::runtime_error("Malformed JSON: missing property script or is not an object.");
|
||||
}
|
||||
if (raw.HasPath("exitscript") && raw["exitscript"].IsMap()) {
|
||||
auto script = scriptFactory->createScript(parent->getGlobalScriptContext().get(), raw["exitscript"]);
|
||||
auto script = scriptFactory->createScript(raw["exitscript"]);
|
||||
if (script) {
|
||||
retval->exitScript = script;
|
||||
} else {
|
||||
@@ -105,43 +102,34 @@ std::shared_ptr<Rule> Rule::createRule(RulePackage* parent, std::string name, Va
|
||||
}
|
||||
|
||||
|
||||
devicerepository::DeviceRepositoryService* Rule::getDeviceRepository() {
|
||||
devicerepository::DeviceRepositoryService* RuleImpl::getDeviceRepository() noexcept {
|
||||
return parent->parent->getDeviceRepository();
|
||||
}
|
||||
|
||||
void Rule::enable() {
|
||||
if (!enabled) {
|
||||
void RuleImpl::setEnabled(bool enabled) noexcept {
|
||||
if (this->enabled != enabled) {
|
||||
if (condition) {
|
||||
condition->enable();
|
||||
condition->setEnabled(enabled);
|
||||
}
|
||||
enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Rule::disable() {
|
||||
if (enabled) {
|
||||
if (condition) {
|
||||
condition->disable();
|
||||
}
|
||||
enabled = false;
|
||||
this->enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Rule::execute(Variant lContext) {
|
||||
void RuleImpl::executeScript(const libvariant::Variant& lContext) {
|
||||
if (enabled && script) {
|
||||
try {
|
||||
script->exec(parent->getGlobalScriptContext().get(), lContext);
|
||||
script->execute(parent->getGlobalScriptContext().lock(), lContext);
|
||||
} catch(std::exception& e) {
|
||||
ROS_ERROR_STREAM(e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Rule::executeExitScript(Variant lContext) {
|
||||
void RuleImpl::executeExitScript(const libvariant::Variant& lContext) {
|
||||
if (enabled && exitScript) {
|
||||
try {
|
||||
exitScript->exec(parent->getGlobalScriptContext().get(), lContext);
|
||||
exitScript->execute(parent->getGlobalScriptContext().lock(), lContext);
|
||||
} catch(std::exception& e) {
|
||||
ROS_ERROR_STREAM(e.what());
|
||||
}
|
||||
@@ -149,13 +137,13 @@ void Rule::executeExitScript(Variant lContext) {
|
||||
}
|
||||
|
||||
|
||||
bool Rule::evaluate() {
|
||||
bool RuleImpl::evaluate() {
|
||||
if (condition) {
|
||||
bool retval = condition->evaluate();
|
||||
if (retval != currentState) {
|
||||
currentState = retval;
|
||||
if (retval) {
|
||||
execute();
|
||||
executeScript();
|
||||
} else {
|
||||
executeExitScript();
|
||||
}
|
||||
@@ -168,13 +156,13 @@ bool Rule::evaluate() {
|
||||
}
|
||||
|
||||
|
||||
void Rule::conditionStateChanged(bool newState, RuleCondition::Category category, Variant lcontext) {
|
||||
if (newState && !currentState && category == RuleCondition::Category::Event) {
|
||||
execute(lcontext);
|
||||
} else if (category == RuleCondition::Category::State && newState != currentState) {
|
||||
void RuleImpl::conditionStateChanged(bool newState, const conditions::ConditionTriggerType& category, const Variant& lcontext) noexcept {
|
||||
if (newState && !currentState && category == conditions::ConditionTriggerType::Event) {
|
||||
executeScript(lcontext);
|
||||
} else if (category == conditions::ConditionTriggerType::State && newState != currentState) {
|
||||
currentState = newState;
|
||||
if (newState) {
|
||||
execute(lcontext);
|
||||
executeScript(lcontext);
|
||||
} else {
|
||||
executeExitScript(lcontext);
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleCondition.h>
|
||||
#include <hos/cosgi/service/ruleengine/rules/Rule.h>
|
||||
#include <hos/cosgi/service/ruleengine/rules/RulePackage.h>
|
||||
|
||||
#include "RulePackageImpl.h"
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
|
||||
// Forward declarations
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace devicerepository {
|
||||
class Device;
|
||||
class DeviceEvent;
|
||||
class DeviceRepositoryService;
|
||||
}
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
class RulePackageImpl;
|
||||
}
|
||||
}
|
||||
namespace scripting {
|
||||
class ScriptingService;
|
||||
class GlobalScriptContext;
|
||||
class Script;
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace utils {
|
||||
class SchemaLoader;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
|
||||
using namespace ::libvariant;
|
||||
|
||||
class RuleImpl : public virtual Rule {
|
||||
private:
|
||||
std::shared_ptr<scripting::Script> script;
|
||||
std::shared_ptr<scripting::Script> exitScript;
|
||||
std::shared_ptr<conditions::RuleCondition> condition;
|
||||
bool enabled = false;
|
||||
bool currentState = false;
|
||||
|
||||
public:
|
||||
RulePackageImpl* const parent;
|
||||
const std::string name;
|
||||
|
||||
RuleImpl(RulePackageImpl* parent, const std::string name);
|
||||
static std::shared_ptr<RuleImpl> createRule(RulePackageImpl* parent, const std::string name, Variant raw);
|
||||
|
||||
virtual RulePackage* getParent() noexcept {
|
||||
return dynamic_cast<RulePackage*>(parent);
|
||||
}
|
||||
|
||||
virtual const std::string& getName() noexcept {
|
||||
return name;
|
||||
}
|
||||
|
||||
virtual bool isActive() noexcept override {
|
||||
return currentState;
|
||||
}
|
||||
virtual bool evaluate() override;
|
||||
virtual void executeScript(const libvariant::Variant& lContext = libvariant::Variant()) override;
|
||||
virtual void executeExitScript(const libvariant::Variant& lContext = libvariant::Variant()) override;
|
||||
|
||||
virtual bool isEnabled() noexcept override {
|
||||
return enabled;
|
||||
}
|
||||
virtual void setEnabled(bool enabled) noexcept override;
|
||||
|
||||
void conditionStateChanged(bool newState, const conditions::ConditionTriggerType& category, const Variant& lcontext = Variant()) noexcept override;
|
||||
|
||||
std::shared_ptr<conditions::RuleCondition> createRuleCondition(const Variant& raw) override;
|
||||
devicerepository::DeviceRepositoryService* getDeviceRepository() noexcept override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+22
-32
@@ -5,29 +5,29 @@
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#include "RulePackage.h"
|
||||
#include "RuleImpl.h"
|
||||
|
||||
#include <ros/ros.h>
|
||||
#include <exception>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
#include "../ruleengine_serviceimpl.h"
|
||||
#include <hos/cosgi/service/ruleengine/rule/Rule.h>
|
||||
#include "../RuleEngineServiceImpl.h"
|
||||
#include "RulePackageImpl.h"
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rule {
|
||||
namespace rules {
|
||||
|
||||
RulePackage::RulePackage(service::ruleengine::RuleEngineServiceImpl* parent, const std::string name, const std::string language, const Variant raw)
|
||||
RulePackageImpl::RulePackageImpl(service::ruleengine::RuleEngineServiceImpl* parent, const std::string name, const std::string language, const Variant raw)
|
||||
: parent(parent), name(name), language(language), rawValue(raw) {}
|
||||
|
||||
RulePackage::~RulePackage() {}
|
||||
RulePackageImpl::~RulePackageImpl() {}
|
||||
|
||||
std::shared_ptr<RulePackage> RulePackage::createRulePackage(service::ruleengine::RuleEngineServiceImpl* parent, std::string name, Variant raw) {
|
||||
std::shared_ptr<RulePackage> retval;
|
||||
if (parent->getRulePackage(name)) {
|
||||
std::shared_ptr<RulePackageImpl> RulePackageImpl::createRulePackage(service::ruleengine::RuleEngineServiceImpl* parent, std::string name, Variant raw) {
|
||||
std::shared_ptr<RulePackageImpl> retval;
|
||||
if (!parent->getRulePackage(name).expired()) {
|
||||
std::stringstream ss;
|
||||
ss << "Could not create package " << name << ": There already exists a rule package with the same name.";
|
||||
throw std::runtime_error(ss.str());
|
||||
@@ -39,7 +39,7 @@ std::shared_ptr<RulePackage> RulePackage::createRulePackage(service::ruleengine:
|
||||
} else {
|
||||
throw std::runtime_error("Rule package JSON is missing language parameter or parameter has wrong type.");
|
||||
}
|
||||
retval = std::make_shared<RulePackage>(parent, name, language, raw);
|
||||
retval = std::make_shared<RulePackageImpl>(parent, name, language, raw);
|
||||
retval->executionService = parent->getExecutionBackend(retval->language);
|
||||
if (retval->executionService) {
|
||||
if (raw.HasPath("globalcontext")) {
|
||||
@@ -48,7 +48,7 @@ std::shared_ptr<RulePackage> RulePackage::createRulePackage(service::ruleengine:
|
||||
if (raw.HasPath("rules") && raw["rules"].IsMap()) {
|
||||
for (auto r : raw["rules"].AsMap()) {
|
||||
try {
|
||||
std::shared_ptr<Rule> rule = Rule::createRule(retval.get(), r.first, r.second);
|
||||
std::shared_ptr<RuleImpl> rule = RuleImpl::createRule(retval.get(), r.first, r.second);
|
||||
if (rule) {
|
||||
retval->rules.insert({r.first, rule});
|
||||
}
|
||||
@@ -70,49 +70,39 @@ std::shared_ptr<RulePackage> RulePackage::createRulePackage(service::ruleengine:
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<Rule> RulePackage::getRule(const std::string& name) {
|
||||
std::shared_ptr<Rule> retval;
|
||||
std::weak_ptr<Rule> RulePackageImpl::getRule(const std::string& name) noexcept {
|
||||
std::weak_ptr<Rule> retval;
|
||||
try {
|
||||
retval = rules.at(name);
|
||||
} catch (...) {}
|
||||
return retval;
|
||||
}
|
||||
|
||||
size_t RulePackage::getRules(std::vector<std::shared_ptr<Rule>>& rules) {
|
||||
size_t retval = 0;
|
||||
std::vector<std::weak_ptr<Rule>> RulePackageImpl::getRules() noexcept {
|
||||
std::vector<std::weak_ptr<Rule>> retval;
|
||||
for (auto item : this->rules) {
|
||||
rules.push_back(item.second);
|
||||
retval++;
|
||||
retval.push_back(dynamic_pointer_cast<Rule>(item.second));
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::shared_ptr<RuleConditionFactory> RulePackage::getConditionFactory(std::string type) {
|
||||
std::shared_ptr<RuleConditionFactory> RulePackageImpl::getConditionFactory(std::string type) {
|
||||
return parent->getRuleConditionFactory(type);
|
||||
}
|
||||
|
||||
|
||||
void RulePackage::enable() {
|
||||
if (!enabled) {
|
||||
void RulePackageImpl::setEnabled(bool enabled) noexcept {
|
||||
if (this->enabled != enabled) {
|
||||
for (auto r : rules) {
|
||||
r.second->enable();
|
||||
r.second->setEnabled(enabled);
|
||||
}
|
||||
enabled = true;
|
||||
this->enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RulePackage::disable() {
|
||||
if (enabled) {
|
||||
for (auto r : rules) {
|
||||
r.second->enable();
|
||||
}
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} /* namespace rule */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
@@ -0,0 +1,97 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rules/RulePackage.h>
|
||||
#include <hos/cosgi/service/scripting/ScriptingService.h>
|
||||
#include "../RuleEngineServiceImpl.h"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
|
||||
// Forward declarations
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
class RuleEngineServiceImpl;
|
||||
class RuleConditionFactory;
|
||||
namespace rules {
|
||||
class RuleImpl;
|
||||
}
|
||||
}
|
||||
namespace scripting {
|
||||
class GlobalScriptContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
|
||||
using namespace ::libvariant;
|
||||
|
||||
class RulePackageImpl
|
||||
: public virtual RulePackage {
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<std::string, std::shared_ptr<RuleImpl>> ruleMap_t;
|
||||
|
||||
service::scripting::ScriptingService* executionService = nullptr;
|
||||
std::shared_ptr<scripting::GlobalScriptContext> globalContext;
|
||||
ruleMap_t rules;
|
||||
Variant rawValue;
|
||||
bool enabled = false;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
static std::shared_ptr<RulePackageImpl> createRulePackage(service::ruleengine::RuleEngineServiceImpl* parent, std::string name, Variant raw);
|
||||
RulePackageImpl(service::ruleengine::RuleEngineServiceImpl* parent, const std::string name, const std::string language, Variant raw);
|
||||
virtual ~RulePackageImpl();
|
||||
|
||||
service::ruleengine::RuleEngineServiceImpl* const parent;
|
||||
const std::string name;
|
||||
const std::string language;
|
||||
|
||||
virtual service::ruleengine::RuleEngineService* getParent() noexcept override {
|
||||
return dynamic_cast<service::ruleengine::RuleEngineService*>(parent);
|
||||
}
|
||||
|
||||
virtual const std::string& getName() noexcept override {
|
||||
return name;
|
||||
};
|
||||
virtual const std::string& getLanguage() noexcept override {
|
||||
return language;
|
||||
}
|
||||
|
||||
virtual std::weak_ptr<Rule> getRule(const std::string& name) noexcept override;
|
||||
virtual std::vector<std::weak_ptr<Rule>> getRules() noexcept override;
|
||||
virtual size_t getRuleCount() noexcept override { return rules.size(); }
|
||||
|
||||
virtual bool isEnabled() noexcept override {
|
||||
return enabled;
|
||||
}
|
||||
virtual void setEnabled(bool enabled) noexcept override;
|
||||
|
||||
virtual service::scripting::ScriptingService* getScriptingService() noexcept override { return executionService; }
|
||||
virtual std::weak_ptr<scripting::GlobalScriptContext> getGlobalScriptContext() noexcept override { return globalContext; }
|
||||
std::shared_ptr<service::ruleengine::RuleConditionFactory> getConditionFactory(std::string type);
|
||||
};
|
||||
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+271
@@ -0,0 +1,271 @@
|
||||
|
||||
|
||||
#include "DeviceMsgCondition.h"
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include "../RuleImpl.h"
|
||||
#include <ros/ros.h>
|
||||
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
namespace conditions {
|
||||
|
||||
|
||||
|
||||
|
||||
void DeviceMsgCondition::notificationReceived(interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||
switch (key) {
|
||||
case devicerepository::DeviceEventType::DEVICE_ADDED:
|
||||
if (!device && this->deviceID.compare(e->device->getDeviceID()) == 0) {
|
||||
ROS_INFO_STREAM("Rule " << parent->getName() << ": Device " << deviceID << " appeared.");
|
||||
device = e->device;
|
||||
parent->getDeviceRepository()->deleteObserver(devicerepository::DeviceEventType::DEVICE_ADDED, this);
|
||||
_registerAsListener();
|
||||
}
|
||||
break;
|
||||
case devicerepository::DeviceEventType::DEVICE_REMOVED:
|
||||
if (device && device->getDeviceID().compare(e->device->getDeviceID()) == 0) {
|
||||
ROS_ERROR_STREAM("Rule " << parent->getName() << ": Device " << deviceID << " disappeared.");
|
||||
device->deleteObserver(this);
|
||||
device = nullptr;
|
||||
parent->getDeviceRepository()->addObserver(devicerepository::DeviceEventType::DEVICE_ADDED, this);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceMsgCondition::setEnabled(bool enabled) noexcept {
|
||||
if (this->enabled != enabled) {
|
||||
if (enabled) {
|
||||
auto repoService = parent->getDeviceRepository();
|
||||
auto device = repoService->getDevice(deviceID);
|
||||
if (!device.expired()) {
|
||||
this->device = device.lock().get();
|
||||
_registerAsListener();
|
||||
} else {
|
||||
ROS_ERROR_STREAM("Rule " << parent->getName() << ": Could not find device " << deviceID);
|
||||
parent->getDeviceRepository()->addObserver(devicerepository::DeviceEventType::DEVICE_ADDED, this);
|
||||
}
|
||||
} else {
|
||||
if (device) {
|
||||
device->deleteObserver(this);
|
||||
device = nullptr;
|
||||
}
|
||||
parent->getDeviceRepository()->deleteObserver(this);
|
||||
}
|
||||
this->enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceMsgCondition::_registerAsListener() {
|
||||
if (device) {
|
||||
for (auto k : _listenerKeys) {
|
||||
device->addObserver(k, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
std::shared_ptr<RuleCondition> DeviceStatusMsgConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
||||
std::shared_ptr<DeviceStatusMsgCondition> retval;
|
||||
std::string deviceID;
|
||||
if (raw.HasPath("deviceid") && raw["deviceid"].IsString()) {
|
||||
deviceID = raw["deviceid"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property deviceid or is not an string.");
|
||||
}
|
||||
std::string msgPointer;
|
||||
if (raw.HasPath("msgpointer")) {
|
||||
if (raw["msgpointer"].IsString()) {
|
||||
msgPointer = raw["msgpointer"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
||||
}
|
||||
}
|
||||
Variant msgValue;
|
||||
if (raw.HasPath("msgvalue")) {
|
||||
msgValue = raw["msgvalue"];
|
||||
}
|
||||
retval = std::make_shared<DeviceStatusMsgCondition>(parent, deviceID, msgPointer, msgValue);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void DeviceStatusMsgCondition::notificationReceived(interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||
switch (e->eventType) {
|
||||
case devicerepository::DeviceEventType::STATUS_UPDATE_RECEIVED:
|
||||
if (device && device == e->device) {
|
||||
auto e2 = static_cast<const devicerepository::DeviceStatusMsgEvent*>(e);
|
||||
bool notify = true;
|
||||
Variant value;
|
||||
if (msgPointer.empty()) {
|
||||
value = e2->statusMsg;
|
||||
} else if (e2->statusMsg.HasPath(msgPointer)) {
|
||||
value = e2->statusMsg.GetPath(msgPointer);
|
||||
} else {
|
||||
notify = false;
|
||||
}
|
||||
if (notify && !msgValue.IsNull()) {
|
||||
if (msgValue != value) {
|
||||
notify = false;
|
||||
}
|
||||
}
|
||||
if (notify) {
|
||||
Variant lcontext;
|
||||
lcontext["event_deviceid"] = Variant(e->device->getDeviceID());
|
||||
lcontext["event_type"] = Variant("statusmsg");
|
||||
lcontext["event_msg"] = e2->statusMsg;
|
||||
notifyStateChangeToParent(true, ConditionTriggerType::Event, lcontext);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DeviceMsgCondition::notificationReceived(o, key, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<RuleCondition> DeviceCommandMsgConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
||||
std::shared_ptr<DeviceCommandMsgCondition> retval;
|
||||
std::string deviceID;
|
||||
if (raw.HasPath("deviceid") && raw["deviceid"].IsString()) {
|
||||
deviceID = raw["deviceid"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property deviceid or is not an string.");
|
||||
}
|
||||
std::string msgPointer;
|
||||
if (raw.HasPath("msgpointer")) {
|
||||
if (raw["msgpointer"].IsString()) {
|
||||
msgPointer = raw["msgpointer"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
||||
}
|
||||
}
|
||||
Variant msgValue;
|
||||
if (raw.HasPath("msgvalue")) {
|
||||
msgValue = raw["msgvalue"];
|
||||
}
|
||||
retval = std::make_shared<DeviceCommandMsgCondition>(parent, deviceID, msgPointer, msgValue);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void DeviceCommandMsgCondition::notificationReceived(interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||
switch (e->eventType) {
|
||||
case devicerepository::DeviceEventType::COMMAND_RECEIVED:
|
||||
if (device && device == e->device) {
|
||||
auto e2 = static_cast<const devicerepository::DeviceCmdMsgEvent*>(e);
|
||||
bool notify = true;
|
||||
Variant value;
|
||||
if (msgPointer.empty()) {
|
||||
value = e2->cmdMsg;
|
||||
} else if (e2->cmdMsg.HasPath(msgPointer)) {
|
||||
value = e2->cmdMsg.GetPath(msgPointer);
|
||||
} else {
|
||||
notify = false;
|
||||
}
|
||||
if (notify && !msgValue.IsNull()) {
|
||||
if (msgValue != value) {
|
||||
notify = false;
|
||||
}
|
||||
}
|
||||
if (notify) {
|
||||
Variant lcontext;
|
||||
lcontext["event_deviceid"] = Variant(e->device->getDeviceID());
|
||||
lcontext["event_type"] = Variant("commandmsg");
|
||||
lcontext["event_msg"] = e2->cmdMsg;
|
||||
notifyStateChangeToParent(true, ConditionTriggerType::Event, lcontext);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DeviceMsgCondition::notificationReceived(o, key, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<RuleCondition> DeviceStateChangeConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
||||
std::shared_ptr<DeviceStateChangeCondition> retval;
|
||||
std::string deviceID;
|
||||
if (raw.HasPath("deviceid") && raw["deviceid"].IsString()) {
|
||||
deviceID = raw["deviceid"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property deviceid or is not an string.");
|
||||
}
|
||||
std::string statePointer;
|
||||
if (raw.HasPath("msgpointer")) {
|
||||
if (raw["msgpointer"].IsString()) {
|
||||
statePointer = raw["msgpointer"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
||||
}
|
||||
}
|
||||
Variant fromValue;
|
||||
if (raw.HasPath("fromvalue")) {
|
||||
fromValue = raw["fromvalue"];
|
||||
}
|
||||
Variant toValue;
|
||||
if (raw.HasPath("tovalue")) {
|
||||
toValue = raw["tovalue"];
|
||||
}
|
||||
retval = std::make_shared<DeviceStateChangeCondition>(parent, deviceID, statePointer, fromValue, toValue);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
void DeviceStateChangeCondition::notificationReceived(interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||
switch (e->eventType) {
|
||||
case devicerepository::DeviceEventType::STATE_CHANGED:
|
||||
if (device && device == e->device) {
|
||||
auto e2 = static_cast<const devicerepository::DeviceStatusMsgEvent*>(e);
|
||||
bool notify = true;
|
||||
Variant current, last;
|
||||
if (msgPointer.empty()) {
|
||||
current = device->getCurrentState();
|
||||
last = device->getLastState();
|
||||
} else if (device->getCurrentState().HasPath(msgPointer) && device->getLastState().HasPath(msgPointer)) {
|
||||
current = device->getCurrentState().GetPath(msgPointer);
|
||||
last = device->getLastState().GetPath(msgPointer);
|
||||
} else {
|
||||
notify = false;
|
||||
}
|
||||
if (notify) {
|
||||
if (current == last) {
|
||||
notify = false;
|
||||
} else if (!fromValue.IsNull() && fromValue != last) {
|
||||
notify = false;
|
||||
} else if (!msgValue.IsNull() && msgValue != current) {
|
||||
notify = false;
|
||||
}
|
||||
}
|
||||
if (notify) {
|
||||
Variant lcontext;
|
||||
lcontext["event_deviceid"] = Variant(e->device->getDeviceID());
|
||||
lcontext["event_type"] = Variant("statechange");
|
||||
lcontext["event_msg"] = e2->statusMsg;
|
||||
notifyStateChangeToParent(true, ConditionTriggerType::Event, lcontext);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DeviceMsgCondition::notificationReceived(o, key, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} /* namespace conditions */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleConditionImpl.h>
|
||||
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include <set>
|
||||
|
||||
|
||||
// main Namespace
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
namespace conditions {
|
||||
|
||||
|
||||
using namespace libvariant;
|
||||
|
||||
|
||||
|
||||
class DeviceMsgCondition
|
||||
: public RuleConditionImpl,
|
||||
public virtual interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent> {
|
||||
|
||||
protected:
|
||||
const std::string deviceID;
|
||||
devicerepository::Device* device = nullptr;
|
||||
const std::string msgPointer;
|
||||
const Variant msgValue;
|
||||
std::set<devicerepository::DeviceEventType> _listenerKeys;
|
||||
|
||||
virtual void _registerAsListener();
|
||||
|
||||
public:
|
||||
DeviceMsgCondition( Rule* parent,
|
||||
ConditionTriggerType category,
|
||||
const std::string& type,
|
||||
const std::string& deviceID,
|
||||
const std::string& msgPointer,
|
||||
const Variant& msgValue,
|
||||
const std::set<devicerepository::DeviceEventType> _listenerKeys )
|
||||
: RuleConditionImpl(parent, category, type), deviceID(deviceID),
|
||||
msgPointer(msgPointer), msgValue(msgValue), _listenerKeys(_listenerKeys) {}
|
||||
|
||||
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
||||
devicerepository::DeviceEvent>::observable_type* o,
|
||||
const devicerepository::DeviceEventType& key,
|
||||
const devicerepository::DeviceEvent* e) noexcept override;
|
||||
|
||||
virtual void setEnabled(bool enabled) noexcept override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class DeviceStatusMsgCondition
|
||||
: public DeviceMsgCondition {
|
||||
|
||||
public:
|
||||
DeviceStatusMsgCondition( Rule* parent,
|
||||
const std::string& deviceID,
|
||||
const std::string& msgPointer,
|
||||
const Variant& msgValue)
|
||||
: DeviceMsgCondition(parent, ConditionTriggerType::Event, "devicestatusmsg", deviceID,
|
||||
msgPointer, msgValue, {devicerepository::DeviceEventType::STATUS_UPDATE_RECEIVED}) {}
|
||||
|
||||
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
||||
devicerepository::DeviceEvent>::observable_type* o,
|
||||
const devicerepository::DeviceEventType& key,
|
||||
const devicerepository::DeviceEvent* e ) noexcept override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class DeviceStatusMsgConditionFactory
|
||||
: public RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<RuleCondition> createCondition(rules::Rule* parent, const Variant& raw) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class DeviceCommandMsgCondition
|
||||
: public DeviceMsgCondition {
|
||||
|
||||
public:
|
||||
DeviceCommandMsgCondition(Rule* parent, const std::string deviceID, const std::string msgPointer, const Variant msgValue)
|
||||
: DeviceMsgCondition(parent, ConditionTriggerType::Event, "devicecommandmsg", deviceID,
|
||||
msgPointer, msgValue, {devicerepository::DeviceEventType::COMMAND_RECEIVED}) {}
|
||||
|
||||
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
||||
devicerepository::DeviceEvent>::observable_type* o,
|
||||
const devicerepository::DeviceEventType& key,
|
||||
const devicerepository::DeviceEvent* e ) noexcept override;
|
||||
};
|
||||
|
||||
|
||||
class DeviceCommandMsgConditionFactory
|
||||
: public RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<RuleCondition> createCondition(rules::Rule* parent, const Variant& raw) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class DeviceStateChangeCondition
|
||||
: public DeviceMsgCondition {
|
||||
|
||||
protected:
|
||||
const Variant fromValue;
|
||||
|
||||
public:
|
||||
DeviceStateChangeCondition( Rule* parent,
|
||||
const std::string deviceID,
|
||||
const std::string statePointer,
|
||||
const Variant fromValue,
|
||||
const Variant toValue )
|
||||
: DeviceMsgCondition(parent, ConditionTriggerType::Event, "devicestatechange", deviceID, statePointer,
|
||||
toValue, {devicerepository::DeviceEventType::STATE_CHANGED}), fromValue(fromValue) {}
|
||||
|
||||
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept override;
|
||||
};
|
||||
|
||||
|
||||
class DeviceStateChangeConditionFactory
|
||||
: public RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<RuleCondition> createCondition(rules::Rule* parent, const Variant& raw) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} /* namespace conditions */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
|
||||
#include "LogicalAndCondition.h"
|
||||
#include <hos/cosgi/service/ruleengine/rules/Rule.h>
|
||||
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
namespace conditions {
|
||||
|
||||
|
||||
|
||||
std::shared_ptr<RuleCondition> LogicalAndConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
||||
std::shared_ptr<LogicalAndCondition> retval;
|
||||
if (raw.HasPath("conditions") && raw["conditions"].IsList() && raw["conditions"].Size() > 0) {
|
||||
retval = std::make_shared<LogicalAndCondition>(parent);
|
||||
for (auto c : raw["conditions"].AsList()) {
|
||||
auto cond = parent->createRuleCondition(c);
|
||||
if (cond) {
|
||||
retval->addChild(cond);
|
||||
} else {
|
||||
throw std::runtime_error("Could not create condition.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property condition or is not a list.");
|
||||
}
|
||||
return std::static_pointer_cast<RuleConditionImpl>(retval);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LogicalAndCondition::addChild(std::shared_ptr<RuleCondition> child) {
|
||||
if (child->getTriggerType() == ConditionTriggerType::Event) {
|
||||
if (eventChildrenCount > 0) {
|
||||
throw new std::runtime_error("Cannot have an and condition with more than two event conditions.");
|
||||
}
|
||||
eventChildrenCount++;
|
||||
} else if (child->getTriggerType() == ConditionTriggerType::State) {
|
||||
stateChildrenCount++;
|
||||
} else {
|
||||
mixedChildrenCount++;
|
||||
}
|
||||
if (mixedChildrenCount > 0 || (eventChildrenCount > 0 && stateChildrenCount > 0)) {
|
||||
triggerType = ConditionTriggerType::Both;
|
||||
} else if (eventChildrenCount > 0 && stateChildrenCount == 0) {
|
||||
triggerType = ConditionTriggerType::Event;
|
||||
} else {
|
||||
triggerType = ConditionTriggerType::State;
|
||||
}
|
||||
RuleCompositeConditionImpl::addChild(child);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LogicalAndCondition::childStateChanged(RuleCondition* child, bool newState, ConditionTriggerType category, const Variant& lcontext) noexcept {
|
||||
if (newState && category == ConditionTriggerType::Event && !currentState && trueChildrenCount >= children.size()-1) {
|
||||
notifyStateChangeToParent(true, category);
|
||||
} else if (category == ConditionTriggerType::State) {
|
||||
if (newState) {
|
||||
trueChildrenCount++;
|
||||
if (!currentState && trueChildrenCount >= children.size()) {
|
||||
currentState = true;
|
||||
notifyStateChangeToParent(true, category, lcontext);
|
||||
}
|
||||
} else {
|
||||
trueChildrenCount--;
|
||||
if (currentState) {
|
||||
currentState = false;
|
||||
notifyStateChangeToParent(false, category, lcontext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool LogicalAndCondition::evaluate() noexcept {
|
||||
// Event conditions always evaluate to false
|
||||
if (triggerType == ConditionTriggerType::Event) {
|
||||
return false;
|
||||
}
|
||||
trueChildrenCount = 0;
|
||||
for (auto c : children) {
|
||||
if (c->evaluate()) {
|
||||
trueChildrenCount++;
|
||||
}
|
||||
}
|
||||
currentState = trueChildrenCount == children.size();
|
||||
return currentState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} /* namespace conditions */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleConditionImpl.h>
|
||||
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||
|
||||
|
||||
// Service Namespace
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
namespace conditions {
|
||||
|
||||
using namespace libvariant;
|
||||
|
||||
|
||||
|
||||
class LogicalAndCondition
|
||||
: public RuleCompositeConditionImpl {
|
||||
|
||||
protected:
|
||||
unsigned eventChildrenCount = 0;
|
||||
unsigned stateChildrenCount = 0;
|
||||
unsigned mixedChildrenCount = 0;
|
||||
unsigned trueChildrenCount = 0;
|
||||
|
||||
public:
|
||||
LogicalAndCondition(Rule* parent) :
|
||||
RuleCompositeConditionImpl(parent, ConditionTriggerType::Both, "logical_and") {}
|
||||
|
||||
virtual void addChild(std::shared_ptr<RuleCondition> child) override;
|
||||
|
||||
virtual void childStateChanged(RuleCondition* child, bool newState, ConditionTriggerType category,
|
||||
const Variant& lcontext = Variant()) noexcept override;
|
||||
|
||||
virtual bool evaluate() noexcept override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class LogicalAndConditionFactory
|
||||
: public RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<RuleCondition> createCondition(rules::Rule* parent, const Variant& raw) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} /* namespace conditions */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
|
||||
#include "LogicalOrCondition.h"
|
||||
#include <hos/cosgi/service/ruleengine/rules/Rule.h>
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
namespace conditions {
|
||||
|
||||
|
||||
|
||||
std::shared_ptr<RuleCondition> LogicalOrConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
||||
std::shared_ptr<LogicalOrCondition> retval;
|
||||
if (raw.HasPath("conditions") && raw["conditions"].IsList() && raw["conditions"].Size() > 0) {
|
||||
retval = std::make_shared<LogicalOrCondition>(parent);
|
||||
for (auto c : raw["conditions"].AsList()) {
|
||||
auto cond = parent->createRuleCondition(c);
|
||||
if (cond) {
|
||||
retval->addChild(cond);
|
||||
} else {
|
||||
throw std::runtime_error("Could not create condition.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property condition or is not a list.");
|
||||
}
|
||||
return std::static_pointer_cast<RuleConditionImpl>(retval);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LogicalOrCondition::addChild(std::shared_ptr<RuleCondition> child) {
|
||||
if (child->getTriggerType() == ConditionTriggerType::Event) {
|
||||
eventChildrenCount++;
|
||||
} else if (child->getTriggerType() == ConditionTriggerType::State) {
|
||||
stateChildrenCount++;
|
||||
} else {
|
||||
mixedChildrenCount++;
|
||||
}
|
||||
if (mixedChildrenCount > 0 || (eventChildrenCount > 0 && stateChildrenCount > 0)) {
|
||||
triggerType = ConditionTriggerType::Both;
|
||||
} else if (eventChildrenCount > 0 && stateChildrenCount == 0) {
|
||||
triggerType = ConditionTriggerType::Event;
|
||||
} else {
|
||||
triggerType = ConditionTriggerType::State;
|
||||
}
|
||||
RuleCompositeConditionImpl::addChild(child);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LogicalOrCondition::childStateChanged(RuleCondition* child, bool newState,
|
||||
ConditionTriggerType category, const Variant& lcontext) noexcept {
|
||||
if (newState && category == ConditionTriggerType::Event && !currentState) {
|
||||
notifyStateChangeToParent(true, category, lcontext);
|
||||
} else if (category == ConditionTriggerType::State) {
|
||||
if (newState) {
|
||||
trueChildrenCount++;
|
||||
if (!currentState) {
|
||||
currentState = true;
|
||||
notifyStateChangeToParent(true, category, lcontext);
|
||||
}
|
||||
} else {
|
||||
trueChildrenCount--;
|
||||
if (currentState && trueChildrenCount <= 0) {
|
||||
currentState = false;
|
||||
notifyStateChangeToParent(false, category, lcontext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool LogicalOrCondition::evaluate() noexcept {
|
||||
// Event conditions always evaluate to false
|
||||
if (triggerType == ConditionTriggerType::Event) {
|
||||
return false;
|
||||
}
|
||||
trueChildrenCount = 0;
|
||||
for (auto c : children) {
|
||||
if (c->evaluate()) {
|
||||
trueChildrenCount++;
|
||||
}
|
||||
}
|
||||
currentState = trueChildrenCount > 0;
|
||||
return currentState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} /* namespace conditions */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleConditionImpl.h>
|
||||
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||
|
||||
|
||||
// Service Namespace
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
namespace conditions {
|
||||
|
||||
using namespace libvariant;
|
||||
|
||||
|
||||
|
||||
class LogicalOrCondition
|
||||
: public RuleCompositeConditionImpl {
|
||||
|
||||
protected:
|
||||
unsigned eventChildrenCount = 0;
|
||||
unsigned stateChildrenCount = 0;
|
||||
unsigned mixedChildrenCount = 0;
|
||||
unsigned trueChildrenCount = 0;
|
||||
|
||||
public:
|
||||
LogicalOrCondition(Rule* parent) :
|
||||
RuleCompositeConditionImpl(parent, ConditionTriggerType::Both, "logical_or") {}
|
||||
|
||||
virtual void addChild(std::shared_ptr<RuleCondition> child) override;
|
||||
virtual void childStateChanged(RuleCondition* child, bool newState, ConditionTriggerType category,
|
||||
const libvariant::Variant& lcontext = libvariant::Variant()) noexcept override;
|
||||
virtual bool evaluate() noexcept override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
class LogicalOrConditionFactory
|
||||
: public RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<RuleCondition> createCondition(rules::Rule* parent, const Variant& raw) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} /* namespace conditions */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleConditionImpl.h>
|
||||
#include "../RuleImpl.h"
|
||||
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
namespace conditions {
|
||||
|
||||
|
||||
|
||||
void RuleConditionImpl::notifyStateChangeToParent(bool newState, ConditionTriggerType category, const libvariant::Variant& lcontext) {
|
||||
if (compositeParent) {
|
||||
compositeParent->childStateChanged(this, newState, category, lcontext);
|
||||
} else {
|
||||
parent->conditionStateChanged(newState, category, lcontext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} /* namespace conditions */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
@@ -93,6 +93,12 @@ catkin_package(
|
||||
## Build ##
|
||||
###########
|
||||
|
||||
include_directories(
|
||||
include/${PROJECT_NAME}/
|
||||
${catkin_INCLUDE_DIRS}
|
||||
${libvariant_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
## Specify additional locations of header files
|
||||
## Your package locations should be listed before other locations
|
||||
# include_directories(include)
|
||||
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
#include <hos/cosgi/service/Interface.h>
|
||||
#include <Variant/Variant.h>
|
||||
#include <memory>
|
||||
|
||||
|
||||
|
||||
// Service Namespace
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace scripting {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Public COSGI interface of an abstract global script context.
|
||||
*
|
||||
* It persists the global context across script executions (to implement global variables).
|
||||
*
|
||||
* Currently it is just an opaque handle that is passed to the script execution handle.
|
||||
*/
|
||||
class GlobalScriptContext
|
||||
: public virtual interface::Object {};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Public COSGI interface of an abstract script object.
|
||||
*
|
||||
* This object is supposed to be stateless, every state is carried in the global script context.
|
||||
*/
|
||||
class Script
|
||||
: public virtual interface::Object {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Execute the script object with the given contexts.
|
||||
*
|
||||
* May return exceptions derived from std::exception.
|
||||
*
|
||||
* \param[in] gContext reference to global context.
|
||||
* \param[in] lContext map with local variables.
|
||||
*/
|
||||
virtual void execute( std::shared_ptr<GlobalScriptContext> gContext = std::shared_ptr<GlobalScriptContext>(),
|
||||
const libvariant::Variant& lContext = libvariant::Variant() ) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Public COSGI interface of a scripting service.
|
||||
*
|
||||
* It offers following functionality:
|
||||
* - Create scripts and related objects.
|
||||
*/
|
||||
class ScriptingService
|
||||
: public virtual interface::Service {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Common name for every scripting service implementation.
|
||||
*/
|
||||
static constexpr const char* SERVICE_NAME = "hos_scripting_service";
|
||||
|
||||
/**
|
||||
* Returns an unique identifier indicating the scripting language.
|
||||
*
|
||||
* \return unique language identifier.
|
||||
*/
|
||||
virtual const char* getLanguage() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Creates and returns a global context object from the given json global context config.
|
||||
*
|
||||
* May return exceptions derived from std::exception.
|
||||
*
|
||||
* \param raw json config.
|
||||
* \return global context object.
|
||||
*/
|
||||
virtual std::shared_ptr<GlobalScriptContext> createGlobalScriptContext(const libvariant::Variant& raw) = 0;
|
||||
|
||||
/**
|
||||
* Creates and returns a script object from the given json script config.
|
||||
*
|
||||
* May return exceptions derived from std::exception.
|
||||
*
|
||||
* \param raw json config.
|
||||
* \return global context object.
|
||||
*/
|
||||
virtual std::shared_ptr<Script> createScript(const libvariant::Variant& raw) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace scripting
|
||||
} // namespace service
|
||||
} // namespace cosgi
|
||||
} // namespace hos
|
||||
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* hos_ruleexecution_service.h
|
||||
*
|
||||
* Created on: 01.05.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_HOS_COSGI_SCRIPTING_HOS_COSGI_SERVICE_SCRIPTING_SCRIPTING_SERVICE_H_
|
||||
#define INCLUDE_HOS_COSGI_SCRIPTING_HOS_COSGI_SERVICE_SCRIPTING_SCRIPTING_SERVICE_H_
|
||||
|
||||
|
||||
#include <hos/cosgi/service/Interface.h>
|
||||
#include <Variant/Variant.h>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace scripting {
|
||||
|
||||
using namespace ::libvariant;
|
||||
|
||||
class GlobalScriptContext : public virtual interface::Object {
|
||||
|
||||
};
|
||||
|
||||
|
||||
class Script : public virtual interface::Object {
|
||||
public:
|
||||
virtual void exec(GlobalScriptContext* gContext, Variant lContext = Variant()) = 0;
|
||||
};
|
||||
|
||||
|
||||
class ScriptingService : public virtual interface::Service {
|
||||
public:
|
||||
static constexpr const char* SERVICE_NAME = "hos_scripting_service";
|
||||
|
||||
virtual std::string getLanguage() = 0;
|
||||
|
||||
virtual std::shared_ptr<GlobalScriptContext> createGlobalScriptContext(::libvariant::Variant raw) = 0;
|
||||
virtual std::shared_ptr<Script> createScript(GlobalScriptContext* gContext, ::libvariant::Variant raw) = 0;
|
||||
};
|
||||
|
||||
|
||||
} // namespace scripting
|
||||
} // namespace service
|
||||
} // namespace cosgi
|
||||
} // namespace hos
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* INCLUDE_HOS_COSGI_SCRIPTING_HOS_COSGI_SERVICE_SCRIPTING_SCRIPTING_SERVICE_H_ */
|
||||
@@ -121,9 +121,10 @@ set(BUNDLE_NAME "hos_scripting_python")
|
||||
|
||||
bundle(hos_cosgi_scripting_python
|
||||
SOURCES
|
||||
${PROJECT_SOURCE_DIR}/src/bundle_activator
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/scripting/python/scripting_serviceimpl
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/scripting/python/PyHOSAPI
|
||||
${PROJECT_SOURCE_DIR}/src/BundleActivator
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/scripting/python/PyScriptingServiceImpl
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/scripting/python/utils/utils
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/scripting/python/hosapi/PyHOSAPI
|
||||
)
|
||||
target_link_libraries(hos_cosgi_scripting_python
|
||||
${catkin_LIBRARIES}
|
||||
|
||||
+17
-20
@@ -1,28 +1,19 @@
|
||||
/*
|
||||
* bundle_activator.cpp
|
||||
*
|
||||
* Created on: 26.04.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
// std
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
// ROS
|
||||
#include <ros/ros.h>
|
||||
// APR
|
||||
#include <apr_general.h>
|
||||
|
||||
#include "ros/ros.h"
|
||||
|
||||
extern "C" {
|
||||
#include "celix/bundle_activator.h"
|
||||
#include "celix/bundle_context.h"
|
||||
#include "celix/service_reference.h"
|
||||
#include "celix/constants.h"
|
||||
}
|
||||
|
||||
// Celix
|
||||
#include <hos/cosgi/celix.h>
|
||||
// CoreService
|
||||
#include "hos/cosgi/service/scripting/python/PyScriptingServiceImpl.h"
|
||||
#include <hos/cosgi/service/core/CoreService.h>
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include "hos/cosgi/service/scripting/python/scripting_serviceimpl.h"
|
||||
#include <memory>
|
||||
|
||||
|
||||
|
||||
using namespace hos::cosgi::service::scripting;
|
||||
@@ -42,6 +33,7 @@ struct UserData {
|
||||
};
|
||||
|
||||
|
||||
|
||||
celix_status_t cb_serviceChanged(void* listener, service_event_pt event) {
|
||||
UserData* myUserData = (UserData*) ((serviceListener*)listener)->handle;
|
||||
if (event->type == OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED) {
|
||||
@@ -63,6 +55,7 @@ celix_status_t cb_serviceChanged(void* listener, service_event_pt event) {
|
||||
return CELIX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
|
||||
celix_status_t status = CELIX_SUCCESS;
|
||||
apr_pool_t* memoryPool = nullptr;
|
||||
@@ -87,6 +80,7 @@ celix_status_t bundleActivator_create(bundle_context_pt context, void **userData
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
|
||||
celix_status_t status = CELIX_SUCCESS;
|
||||
if (userData != nullptr) {
|
||||
@@ -132,6 +126,7 @@ celix_status_t bundleActivator_start(void * userData, bundle_context_pt context)
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) {
|
||||
celix_status_t status = CELIX_ILLEGAL_STATE;
|
||||
if (userData != nullptr) {
|
||||
@@ -152,6 +147,7 @@ celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context)
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
|
||||
celix_status_t status = CELIX_ILLEGAL_STATE;
|
||||
if (userData != nullptr) {
|
||||
@@ -168,3 +164,4 @@ celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt contex
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
+68
-40
@@ -1,17 +1,8 @@
|
||||
/*
|
||||
* hos_cosgi_ruleexecution_python_impl.cpp
|
||||
*
|
||||
* Created on: 01.05.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#include "scripting_serviceimpl.h"
|
||||
|
||||
#include "PyScriptingServiceImpl.h"
|
||||
#include <hos/cosgi/service/core/CoreService.h>
|
||||
|
||||
#include "PyHOSAPI.h"
|
||||
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include "hosapi/PyHOSAPI.h"
|
||||
|
||||
|
||||
|
||||
@@ -21,52 +12,77 @@ namespace service {
|
||||
namespace scripting {
|
||||
namespace python {
|
||||
|
||||
template<> const char* implementation::ServiceInfo<PyScriptingService>::name = service::scripting::python::PyScriptingService::SERVICE_NAME;
|
||||
template<> const int implementation::ServiceInfo<PyScriptingService>::major = 0;
|
||||
template<> const int implementation::ServiceInfo<PyScriptingService>::minor = 8;
|
||||
|
||||
void PyScriptingService::setCoreService(service::core::CoreService* coreService) {
|
||||
|
||||
// Service information
|
||||
template<> const char* implementation::ServiceInfo<PyScriptingService>::name = service::scripting::python::PyScriptingService::SERVICE_NAME;
|
||||
template<> const int implementation::ServiceInfo<PyScriptingService>::major = 1;
|
||||
template<> const int implementation::ServiceInfo<PyScriptingService>::minor = 0;
|
||||
|
||||
|
||||
|
||||
void PyScriptingService::setCoreService(service::core::CoreService* coreService) noexcept {
|
||||
if (coreService && !this->coreService) {
|
||||
this->coreService = coreService;
|
||||
this->nodehandle = &coreService->getPrivateNodeHandle();
|
||||
int major = 0, minor = 0;
|
||||
coreService->getServiceVersion(major, minor);
|
||||
ROS_INFO_STREAM("PyRuleExecutionService: Found HOSCoreService Version " << major << "." << minor);
|
||||
ROS_INFO_STREAM("PyScriptingService: Found CoreService Version " << major << "." << minor);
|
||||
if (repoService) {
|
||||
init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PyScriptingService::setRepoService(devicerepository::DeviceRepositoryService* repoService) {
|
||||
void PyScriptingService::setRepoService(devicerepository::DeviceRepositoryService* repoService) noexcept {
|
||||
if (repoService && !this->repoService) {
|
||||
this->repoService = repoService;
|
||||
int major = 0, minor = 0;
|
||||
repoService->getServiceVersion(major, minor);
|
||||
ROS_INFO_STREAM("PyRuleExecutionService: Found HOSDeviceRepositoryService Version " << major << "." << minor);
|
||||
ROS_INFO_STREAM("PyScriptingService: Found DeviceRepositoryService Version " << major << "." << minor);
|
||||
if (coreService) {
|
||||
init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PyScriptingService::init() {
|
||||
void PyScriptingService::init() noexcept {
|
||||
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||
|
||||
// Initialize Python
|
||||
Py_Initialize();
|
||||
|
||||
// Import __main__
|
||||
boost::python::object main_module = boost::python::import("__main__");
|
||||
pyGlobalScope = main_module.attr("__dict__");// Load the sys module.
|
||||
|
||||
// Create default global scope
|
||||
pyGlobalScope = main_module.attr("__dict__");
|
||||
|
||||
// import sys and get version
|
||||
boost::python::object sys = boost::python::import("sys");
|
||||
std::string version = boost::python::extract<std::string>(sys.attr("version"));
|
||||
ROS_INFO_STREAM("PyRuleExecutionService: Python Version: " << version);
|
||||
ROS_INFO_STREAM("PyScriptingService: Python Version: " << version);
|
||||
|
||||
// Initialize HOS Python API
|
||||
inithos();
|
||||
deviceService.reset(new hosapi::PyDeviceRepositoryWrapper(repoService));
|
||||
|
||||
initialized = true;
|
||||
ROS_INFO_STREAM("PyRuleExecutionService: Initialized and Ready.");
|
||||
}
|
||||
|
||||
std::shared_ptr<service::scripting::GlobalScriptContext> PyScriptingService::createGlobalScriptContext(Variant raw) {
|
||||
|
||||
std::shared_ptr<service::scripting::GlobalScriptContext> PyScriptingService::createGlobalScriptContext(const Variant& raw) {
|
||||
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||
std::shared_ptr<PyGlobalScriptContext> retval;
|
||||
|
||||
// Retrieve script code and execute it
|
||||
if (raw.HasPath("code") && raw["code"].IsString()) {
|
||||
retval = std::make_shared<PyGlobalScriptContext>(this->pyGlobalScope, raw["code"].AsString());
|
||||
retval = std::make_shared<PyGlobalScriptContext>(this, this->pyGlobalScope, raw["code"].AsString());
|
||||
try {
|
||||
boost::python::object result = boost::python::exec(retval->getCode().c_str(), pyGlobalScope);
|
||||
// When no local context is given, all variable created during execution comes into the global scope
|
||||
boost::python::object result = boost::python::exec(retval->getScriptCode().c_str(), pyGlobalScope);
|
||||
|
||||
} catch(boost::python::error_already_set const &) {
|
||||
PyErr_Print();
|
||||
throw std::runtime_error("Python error during global context creation.");
|
||||
@@ -75,10 +91,13 @@ std::shared_ptr<service::scripting::GlobalScriptContext> PyScriptingService::cre
|
||||
return std::static_pointer_cast<service::scripting::GlobalScriptContext>(retval);
|
||||
}
|
||||
|
||||
std::shared_ptr<service::scripting::Script> PyScriptingService::createScript(service::scripting::GlobalScriptContext* gContext, Variant raw) {
|
||||
|
||||
std::shared_ptr<service::scripting::Script> PyScriptingService::createScript(const Variant& raw) {
|
||||
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||
std::shared_ptr<PyScript> retval;
|
||||
// Retrieve script code and create script object
|
||||
if (raw.HasPath("code") && raw["code"].IsString()) {
|
||||
retval = std::make_shared<PyScript>(raw["code"].AsString(), *this);
|
||||
retval = std::make_shared<PyScript>(this, raw["code"].AsString());
|
||||
}
|
||||
return std::static_pointer_cast<service::scripting::Script>(retval);
|
||||
}
|
||||
@@ -86,24 +105,33 @@ std::shared_ptr<service::scripting::Script> PyScriptingService::createScript(ser
|
||||
|
||||
|
||||
|
||||
void PyScript::exec(service::scripting::GlobalScriptContext* gContext, Variant lContext) {
|
||||
|
||||
|
||||
void PyScript::execute( std::shared_ptr<GlobalScriptContext> gContext, const libvariant::Variant& lContext ) {
|
||||
try {
|
||||
boost::python::object& gcont = service.getPyGlobalScope();
|
||||
auto gCont = dynamic_pointer_cast<PyGlobalScriptContext>(gContext);
|
||||
|
||||
// Get global scope
|
||||
boost::python::object* gscope;
|
||||
if (gContext) {
|
||||
gcont = dynamic_cast<PyGlobalScriptContext*>(gContext)->getPyGlobalContext();
|
||||
}
|
||||
boost::python::object lcont;
|
||||
if (!lContext.IsNull()) {
|
||||
lcont = convertVariantToBoostPython(lContext);
|
||||
//gcont["local"] = lcont;
|
||||
gscope = &dynamic_pointer_cast<PyGlobalScriptContext>(gContext)->getPyObject();
|
||||
} else {
|
||||
lcont = boost::python::dict();
|
||||
gscope = &service->getPyDefaultScrope();
|
||||
}
|
||||
inithos();
|
||||
PyDeviceRepositoryWrapper deviceService(service.getDeviceRepository());
|
||||
lcont["Devices"] = boost::python::object(boost::python::ptr(&deviceService));
|
||||
gcont["Devices"] = boost::python::object(deviceService);
|
||||
boost::python::object result = boost::python::exec(code.c_str(), gcont, lcont);
|
||||
|
||||
// Create local scope
|
||||
boost::python::object lscope;
|
||||
if (!lContext.IsNull() && lContext.IsMap()) {
|
||||
lscope = utils::convertVariantToBoostPython(lContext);
|
||||
//gscope["local"] = lscope;
|
||||
} else {
|
||||
lscope = boost::python::dict();
|
||||
}
|
||||
lscope["Devices"] = boost::python::object(boost::python::ptr(service->getDeviceService()));
|
||||
|
||||
// Execute script scope
|
||||
boost::python::object result = boost::python::exec(code.c_str(), *gscope, lscope);
|
||||
|
||||
} catch(boost::python::error_already_set const &) {
|
||||
PyErr_Print();
|
||||
throw std::runtime_error("Python error during execution.");
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <hos/cosgi/service/scripting/ScriptingService.h>
|
||||
// hos includes
|
||||
#include <hos/cosgi/service/Implementation.h>
|
||||
#include <hos/cosgi/service/core/CoreService.h>
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include "hosapi/PyHOSAPI.h"
|
||||
// libvariant includes
|
||||
#include <Variant/Variant.h>
|
||||
// ROS includes
|
||||
#include <ros/ros.h>
|
||||
// std includes
|
||||
#include <memory>
|
||||
// boost includes
|
||||
#include <boost/python.hpp>
|
||||
|
||||
|
||||
|
||||
// Service Namespace
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace scripting {
|
||||
namespace python {
|
||||
|
||||
|
||||
// forward declarations
|
||||
class PyScriptingService;
|
||||
|
||||
|
||||
using namespace libvariant;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Python implementation of GlobalScriptContext.
|
||||
*/
|
||||
class PyGlobalScriptContext
|
||||
: public virtual service::scripting::GlobalScriptContext {
|
||||
|
||||
private:
|
||||
|
||||
PyScriptingService* service;
|
||||
boost::python::object gContext;
|
||||
std::string code;
|
||||
|
||||
public:
|
||||
|
||||
PyGlobalScriptContext(PyScriptingService* service, const boost::python::object& gContext, const std::string& code)
|
||||
: service(service), gContext(gContext), code(code) {}
|
||||
|
||||
/* Internal */
|
||||
|
||||
const std::string& getScriptCode() noexcept {
|
||||
return code;
|
||||
}
|
||||
|
||||
boost::python::object& getPyObject() noexcept {
|
||||
return gContext;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Python implementation of Script.
|
||||
*/
|
||||
class PyScript
|
||||
: public virtual service::scripting::Script {
|
||||
|
||||
private:
|
||||
|
||||
PyScriptingService* service;
|
||||
std::string code;
|
||||
|
||||
public:
|
||||
|
||||
PyScript(PyScriptingService* service, const std::string& code)
|
||||
: code(code), service(service) {}
|
||||
|
||||
|
||||
/* Public Service Implementations */
|
||||
|
||||
virtual void execute( std::shared_ptr<GlobalScriptContext> gContext = std::shared_ptr<GlobalScriptContext>(),
|
||||
const libvariant::Variant& lContext = libvariant::Variant() ) override;
|
||||
|
||||
|
||||
/* Internal */
|
||||
|
||||
const std::string& getScriptCode() noexcept {
|
||||
return code;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of device repository service
|
||||
**/
|
||||
class PyScriptingService
|
||||
: public virtual service::scripting::ScriptingService,
|
||||
public virtual implementation::Service<PyScriptingService> {
|
||||
|
||||
private:
|
||||
|
||||
std::recursive_mutex serviceMutex;
|
||||
|
||||
service::core::CoreService* coreService = nullptr;;
|
||||
devicerepository::DeviceRepositoryService* repoService = nullptr;;
|
||||
ros::NodeHandle* nodehandle = nullptr;
|
||||
|
||||
boost::python::object pyGlobalScope;
|
||||
std::unique_ptr<hosapi::PyDeviceRepositoryWrapper> deviceService;
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
void init() noexcept;
|
||||
|
||||
public:
|
||||
|
||||
/** Language identifier. */
|
||||
static constexpr const char* LANGUAGE = "python";
|
||||
|
||||
|
||||
/* Initialization */
|
||||
|
||||
void setCoreService(service::core::CoreService* coreService) noexcept;
|
||||
void setRepoService(devicerepository::DeviceRepositoryService* repoService) noexcept;
|
||||
|
||||
|
||||
/* Public Service Implementations */
|
||||
|
||||
virtual const char* getLanguage() noexcept override {
|
||||
return LANGUAGE;
|
||||
}
|
||||
|
||||
virtual std::shared_ptr<scripting::GlobalScriptContext> createGlobalScriptContext(const Variant& raw) override;
|
||||
|
||||
virtual std::shared_ptr<scripting::Script> createScript(const Variant& raw) override;
|
||||
|
||||
|
||||
/* Internal */
|
||||
|
||||
bool isInitialized() noexcept {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
boost::python::object& getPyDefaultScrope() noexcept {
|
||||
return pyGlobalScope;
|
||||
}
|
||||
|
||||
hosapi::PyDeviceRepositoryWrapper* getDeviceService() noexcept {
|
||||
return deviceService.get();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace python
|
||||
} // namespace scripting
|
||||
} // namespace service
|
||||
} // namespace cosgi
|
||||
} // namespace hos
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
|
||||
|
||||
#include "PyHOSAPI.h"
|
||||
|
||||
/**
|
||||
* Python HOS API declaration.
|
||||
*/
|
||||
BOOST_PYTHON_MODULE(hos)
|
||||
{
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace hos::cosgi::service::scripting::python::hosapi;
|
||||
|
||||
// Device class
|
||||
class_<PyDeviceWrapper>("Device", no_init)
|
||||
.def("deviceID", &PyDeviceWrapper::deviceID)
|
||||
.def("sendCommand", &PyDeviceWrapper::sendCommand);
|
||||
|
||||
// Device Repository class.
|
||||
class_<PyDeviceRepositoryWrapper>("DeviceRepository", no_init)
|
||||
.def("getDevice", &PyDeviceRepositoryWrapper::getDevice)
|
||||
.def("__getitem__", &PyDeviceRepositoryWrapper::getDevice)
|
||||
.def("__len__", &PyDeviceRepositoryWrapper::deviceCount)
|
||||
.def("keys", &PyDeviceRepositoryWrapper::deviceIDs);
|
||||
|
||||
};
|
||||
|
||||
+47
-30
@@ -1,53 +1,72 @@
|
||||
/*
|
||||
* PyHOSAPI.h
|
||||
*
|
||||
* Created on: 19.05.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#ifndef SRC_HOS_COSGI_SERVICE_SCRIPTING_PYTHON_PYHOSAPI_H_
|
||||
#define SRC_HOS_COSGI_SERVICE_SCRIPTING_PYTHON_PYHOSAPI_H_
|
||||
#pragma once
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <hos/cosgi/service/scripting/scripting_service.h>
|
||||
|
||||
#include <hos/cosgi/service/scripting/ScriptingService.h>
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include <boost/python.hpp>
|
||||
#include "../utils/utils.h"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This function declares the python hos module.
|
||||
*/
|
||||
extern "C" void inithos();
|
||||
|
||||
|
||||
|
||||
// main namespace
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace scripting {
|
||||
namespace python {
|
||||
|
||||
class PyScriptingService;
|
||||
namespace hosapi {
|
||||
|
||||
|
||||
boost::python::object convertVariantToBoostPython(Variant var);
|
||||
|
||||
Variant convertBoostPythonTovariant(boost::python::object obj);
|
||||
|
||||
|
||||
/**
|
||||
* Python HOS API wrapper for devicerepository::Device.
|
||||
*/
|
||||
class PyDeviceWrapper {
|
||||
|
||||
private:
|
||||
|
||||
devicerepository::Device* device;
|
||||
|
||||
public:
|
||||
PyDeviceWrapper(devicerepository::Device* device) : device(device) {}
|
||||
|
||||
std::string deviceID() { return device->getDeviceID(); }
|
||||
PyDeviceWrapper(devicerepository::Device* device)
|
||||
: device(device) {}
|
||||
|
||||
void sendCommand(boost::python::object cmd) {
|
||||
device->sendCommand(convertBoostPythonTovariant(cmd));
|
||||
const std::string deviceID() noexcept {
|
||||
return device->getDeviceID();
|
||||
}
|
||||
|
||||
void sendCommand(const boost::python::object& cmd) {
|
||||
device->sendCommand(utils::convertBoostPythonTovariant(cmd));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class PyDeviceRepositoryWrapper {
|
||||
private:
|
||||
devicerepository::DeviceRepositoryService* service;
|
||||
public:
|
||||
PyDeviceRepositoryWrapper(devicerepository::DeviceRepositoryService* service) : service(service) {}
|
||||
|
||||
PyDeviceWrapper getDevice(std::string name) {
|
||||
/**
|
||||
* Python HOS API wrapper for devicerepository::DeviceRepositoryService.
|
||||
*/
|
||||
class PyDeviceRepositoryWrapper {
|
||||
|
||||
private:
|
||||
|
||||
devicerepository::DeviceRepositoryService* service;
|
||||
|
||||
public:
|
||||
|
||||
PyDeviceRepositoryWrapper(devicerepository::DeviceRepositoryService* service)
|
||||
: service(service) {}
|
||||
|
||||
PyDeviceWrapper getDevice(const std::string& name) {
|
||||
return PyDeviceWrapper(service->getDevice(name).lock().get());
|
||||
}
|
||||
|
||||
@@ -62,17 +81,15 @@ public:
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
extern "C" void inithos();
|
||||
|
||||
|
||||
} // namespace hosapi
|
||||
} // namespace python
|
||||
} // namespace scripting
|
||||
} // namespace service
|
||||
} // namespace cosgi
|
||||
} // namespace hos
|
||||
|
||||
|
||||
|
||||
#endif /* SRC_HOS_COSGI_SERVICE_SCRIPTING_PYTHON_PYHOSAPI_H_ */
|
||||
-111
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* hos_cosgi_ruleexecution_python_impl.h
|
||||
*
|
||||
* Created on: 01.05.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#ifndef SRC_HOS_COSGI_SERVICE_SCRIPTING_PYTHON_SCRIPTING_SERVICEIMPL_H_
|
||||
#define SRC_HOS_COSGI_SERVICE_SCRIPTING_PYTHON_SCRIPTING_SERVICEIMPL_H_
|
||||
|
||||
#include <ros/ros.h>
|
||||
#include <Variant/Variant.h>
|
||||
#include <boost/python.hpp>
|
||||
#include <hos/cosgi/service/scripting/scripting_service.h>
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include <hos/cosgi/service/Implementation.h>
|
||||
#include <memory>
|
||||
|
||||
|
||||
// Forward declarations
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace core {
|
||||
class CoreService;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace scripting {
|
||||
namespace python {
|
||||
|
||||
class PyScriptingService;
|
||||
using namespace ::libvariant;
|
||||
|
||||
class PyGlobalScriptContext : public virtual service::scripting::GlobalScriptContext {
|
||||
private:
|
||||
boost::python::object& gContext;
|
||||
std::string code;
|
||||
public:
|
||||
PyGlobalScriptContext(boost::python::object& gContext, std::string code)
|
||||
: gContext(gContext), code(code) {}
|
||||
std::string getCode() { return code; }
|
||||
boost::python::object& getPyGlobalContext() { return gContext; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
class PyScript : public virtual service::scripting::Script {
|
||||
private:
|
||||
std::string code;
|
||||
PyScriptingService& service;
|
||||
public:
|
||||
PyScript(std::string code, PyScriptingService& service) : code(code), service(service) {}
|
||||
std::string getCode() { return code; }
|
||||
virtual void exec(service::scripting::GlobalScriptContext* gContext, Variant lContext = Variant());
|
||||
};
|
||||
|
||||
|
||||
class PyScriptingService;
|
||||
class PyScriptingService : public virtual service::scripting::ScriptingService, public virtual implementation::Service<PyScriptingService> {
|
||||
private:
|
||||
service::core::CoreService* coreService = nullptr;;
|
||||
devicerepository::DeviceRepositoryService* repoService = nullptr;;
|
||||
ros::NodeHandle* nodehandle = nullptr;
|
||||
|
||||
boost::python::object pyGlobalScope;
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
void init();
|
||||
|
||||
public:
|
||||
static constexpr const char* LANGUAGE = "python";
|
||||
|
||||
/* Initialization */
|
||||
|
||||
void setCoreService(service::core::CoreService* coreService);
|
||||
void setRepoService(devicerepository::DeviceRepositoryService* repoService);
|
||||
|
||||
/* Public Service Implementations */
|
||||
virtual std::string getLanguage() { return LANGUAGE; }
|
||||
|
||||
virtual std::shared_ptr<scripting::GlobalScriptContext> createGlobalScriptContext(Variant raw);
|
||||
virtual std::shared_ptr<scripting::Script> createScript(scripting::GlobalScriptContext* gContext, Variant raw);
|
||||
|
||||
/* Internal Stuff */
|
||||
|
||||
bool isInitialized() { return initialized; }
|
||||
|
||||
boost::python::object& getPyGlobalScope() { return pyGlobalScope; }
|
||||
|
||||
devicerepository::DeviceRepositoryService* getDeviceRepository() { return repoService; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace python
|
||||
} // namespace scripting
|
||||
} // namespace service
|
||||
} // namespace cosgi
|
||||
} // namespace hos
|
||||
|
||||
|
||||
#endif /* SRC_HOS_COSGI_SERVICE_SCRIPTING_PYTHON_SCRIPTING_SERVICEIMPL_H_ */
|
||||
+19
-36
@@ -1,39 +1,21 @@
|
||||
/*
|
||||
* PyHOSAPI.cpp
|
||||
*
|
||||
* Created on: 19.05.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#include "utils.h"
|
||||
#include "ros/ros.h"
|
||||
|
||||
|
||||
|
||||
#include "PyHOSAPI.h"
|
||||
#include <ros/ros.h>
|
||||
|
||||
|
||||
// main namespace
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace scripting {
|
||||
namespace python {
|
||||
namespace utils {
|
||||
|
||||
|
||||
BOOST_PYTHON_MODULE(hos)
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
||||
class_<PyDeviceWrapper>("Device", no_init)
|
||||
.def("deviceID", &PyDeviceWrapper::deviceID)
|
||||
.def("sendCommand", &PyDeviceWrapper::sendCommand) ;
|
||||
|
||||
class_<PyDeviceRepositoryWrapper>("DeviceRepository", no_init)
|
||||
.def("getDevice", &PyDeviceRepositoryWrapper::getDevice)
|
||||
.def("__getitem__", &PyDeviceRepositoryWrapper::getDevice)
|
||||
.def("__len__", &PyDeviceRepositoryWrapper::deviceCount)
|
||||
.def("keys", &PyDeviceRepositoryWrapper::deviceIDs) ;
|
||||
}
|
||||
|
||||
boost::python::object convertVariantToBoostPython(Variant var) {
|
||||
boost::python::object convertVariantToBoostPython(const libvariant::Variant& var) noexcept {
|
||||
if (var.IsBool()) {
|
||||
return boost::python::object(var.AsBool());
|
||||
} else if (var.IsFloat()) {
|
||||
@@ -63,45 +45,46 @@ boost::python::object convertVariantToBoostPython(Variant var) {
|
||||
}
|
||||
|
||||
|
||||
Variant convertBoostPythonTovariant(boost::python::object obj) {
|
||||
Variant retval;
|
||||
libvariant::Variant convertBoostPythonTovariant(const boost::python::object& obj) noexcept {
|
||||
libvariant::Variant retval;
|
||||
if (!obj.is_none()) {
|
||||
if (PyObject_TypeCheck(obj.ptr(), &PyString_Type)) {
|
||||
retval = Variant(boost::python::extract<std::string>(obj));
|
||||
retval = libvariant::Variant(boost::python::extract<std::string>(obj));
|
||||
} else if (PyObject_TypeCheck(obj.ptr(), &PyBool_Type)) {
|
||||
retval = Variant(boost::python::extract<bool>(obj));
|
||||
retval = libvariant::Variant(boost::python::extract<bool>(obj));
|
||||
} else if (PyObject_TypeCheck(obj.ptr(), &PyFloat_Type)) {
|
||||
retval = Variant(boost::python::extract<double>(obj));
|
||||
retval = libvariant::Variant(boost::python::extract<double>(obj));
|
||||
} else if (PyObject_TypeCheck(obj.ptr(), &PyInt_Type)) {
|
||||
retval = Variant(boost::python::extract<int>(obj));
|
||||
retval = libvariant::Variant(boost::python::extract<int>(obj));
|
||||
} else if (PyObject_TypeCheck(obj.ptr(), &PyDict_Type)) {
|
||||
boost::python::dict dict = boost::python::extract<boost::python::dict>(obj);
|
||||
for (int i = 0; i < boost::python::len(dict); i++) {
|
||||
auto k = dict.keys()[i];
|
||||
Variant key = convertBoostPythonTovariant(k);
|
||||
Variant value = convertBoostPythonTovariant(dict[k]);
|
||||
libvariant::Variant key = convertBoostPythonTovariant(k);
|
||||
libvariant::Variant value = convertBoostPythonTovariant(dict[k]);
|
||||
retval[key.AsString()] = value;
|
||||
}
|
||||
} else if (PyObject_TypeCheck(obj.ptr(), &PyList_Type)) {
|
||||
boost::python::list list = boost::python::extract<boost::python::list>(obj);
|
||||
for (int i = 0; i < boost::python::len(list); i++) {
|
||||
auto v = list[i];
|
||||
Variant value = convertBoostPythonTovariant(v);
|
||||
libvariant::Variant value = convertBoostPythonTovariant(v);
|
||||
retval.Append(value);
|
||||
}
|
||||
} else {
|
||||
ROS_ERROR("Unknown PyObject type encountered while converting to Variant");
|
||||
return Variant();
|
||||
return libvariant::Variant();
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace utils
|
||||
} // namespace python
|
||||
} // namespace scripting
|
||||
} // namespace ruleengine
|
||||
} // namespace service
|
||||
} // namespace cosgi
|
||||
} // namespace hos
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
|
||||
|
||||
// main namespace
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace scripting {
|
||||
namespace python {
|
||||
namespace utils {
|
||||
|
||||
|
||||
/**
|
||||
* Converts a Variant into a boost::python::object.
|
||||
*
|
||||
* \param[in] variant object.
|
||||
* \return boost python object.
|
||||
*/
|
||||
boost::python::object convertVariantToBoostPython(const libvariant::Variant& var) noexcept;
|
||||
|
||||
|
||||
/**
|
||||
* Converts a boost::python::object into a Variant.
|
||||
*
|
||||
* \param[in] boost python object.
|
||||
* \return variant object.
|
||||
*/
|
||||
libvariant::Variant convertBoostPythonTovariant(const boost::python::object& obj) noexcept;
|
||||
|
||||
|
||||
|
||||
} // namespace utils
|
||||
} // namespace python
|
||||
} // namespace ruleengine
|
||||
} // namespace service
|
||||
} // namespace cosgi
|
||||
} // namespace hos
|
||||
|
||||
+7
-2
@@ -80,8 +80,13 @@ void DevicesHTTPResource::render_GET(const httpserver::http_request& req, httpse
|
||||
for (int i = prefixPathPieces+1; i < req.get_path_pieces_size(); i++) {
|
||||
path.push_back(req.get_path_piece(i));
|
||||
}
|
||||
setDeviceState(device.lock().get(), setValue, path);
|
||||
*res = new http_response(http_response_builder("OK", 200).string_response());
|
||||
try {
|
||||
setDeviceState(device.lock().get(), setValue, path);
|
||||
*res = new http_response(http_response_builder("OK", 200).string_response());
|
||||
} catch (std::exception& e) {
|
||||
auto msg = (boost::format("ERROR: %1%") % e.what()).str();
|
||||
*res = new http_response(http_response_builder(msg , 400).string_response());
|
||||
}
|
||||
} else {
|
||||
std::string info;
|
||||
if (req.get_path_pieces_size() > prefixPathPieces+1) {
|
||||
|
||||
@@ -14,16 +14,22 @@ namespace utils {
|
||||
|
||||
|
||||
|
||||
class SchemaLoader: public libvariant::SchemaLoader {
|
||||
class SchemaLoader
|
||||
: public libvariant::SchemaLoader {
|
||||
|
||||
private:
|
||||
std::string ros_param_ns;
|
||||
std::string prefix;
|
||||
ros::NodeHandle nodeHandle;
|
||||
|
||||
bool loadTypeSchema(std::string schema);
|
||||
|
||||
public:
|
||||
SchemaLoader(std::string ns = "/hos/types/repository", std::string prefix = "hos:schema://")
|
||||
SchemaLoader(const std::string& ns = "/hos/types/repository", const std::string& prefix = "hos:schema://")
|
||||
: ros_param_ns(ns), prefix(prefix), nodeHandle("~") {}
|
||||
virtual bool HandleMissing(const std::string &uri, LoaderError &error);
|
||||
|
||||
virtual bool HandleMissing(const std::string &uri, LoaderError &error) override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user