23#include <baseapp/run.h>
24#include <logging/logger.h>
25#include <plugins/clips/aspect/clips_env_manager.h>
26#include <plugins/clips/aspect/clips_feature.h>
27#include <utils/time/time.h>
32#include <clips/clips.h>
37#define ROUTER_NAME "fawkeslog"
43 CLIPSLogger(Logger *logger,
const char *component = NULL)
47 component_ = strdup(component);
61 log(
const char *logical_name,
const char *str)
63 if (strcmp(str,
"\n") == 0) {
64 if (strcmp(logical_name,
"debug") == 0 || strcmp(logical_name,
"logdebug") == 0
65 || strcmp(logical_name, WTRACE) == 0) {
66 logger_->log_debug(component_ ? component_ :
"CLIPS",
"%s", buffer_.c_str());
67 }
else if (strcmp(logical_name,
"warn") == 0 || strcmp(logical_name,
"logwarn") == 0
68 || strcmp(logical_name, WWARNING) == 0) {
69 logger_->log_warn(component_ ? component_ :
"CLIPS",
"%s", buffer_.c_str());
70 }
else if (strcmp(logical_name,
"error") == 0 || strcmp(logical_name,
"logerror") == 0
71 || strcmp(logical_name, WERROR) == 0) {
72 logger_->log_error(component_ ? component_ :
"CLIPS",
"%s", buffer_.c_str());
73 }
else if (strcmp(logical_name, WDIALOG) == 0) {
76 logger_->log_info(component_ ? component_ :
"CLIPS",
"%s", buffer_.c_str());
91class CLIPSContextMaintainer
94 CLIPSContextMaintainer(Logger *logger,
const char *log_component_name)
95 : logger(logger, log_component_name)
99 ~CLIPSContextMaintainer()
108log_router_query(
void *env,
char *logical_name)
110 if (strcmp(logical_name,
"l") == 0)
112 if (strcmp(logical_name,
"info") == 0)
114 if (strcmp(logical_name,
"debug") == 0)
116 if (strcmp(logical_name,
"warn") == 0)
118 if (strcmp(logical_name,
"error") == 0)
120 if (strcmp(logical_name,
"loginfo") == 0)
122 if (strcmp(logical_name,
"logdebug") == 0)
124 if (strcmp(logical_name,
"logwarn") == 0)
126 if (strcmp(logical_name,
"logerror") == 0)
128 if (strcmp(logical_name,
"stdout") == 0)
130 if (strcmp(logical_name, WTRACE) == 0)
132 if (strcmp(logical_name, WDIALOG) == 0)
134 if (strcmp(logical_name, WWARNING) == 0)
136 if (strcmp(logical_name, WERROR) == 0)
138 if (strcmp(logical_name, WDISPLAY) == 0)
144log_router_print(
void *env,
char *logical_name,
char *str)
146 void * rc = GetEnvironmentRouterContext(env);
147 CLIPSLogger *logger =
static_cast<CLIPSLogger *
>(rc);
148 logger->
log(logical_name, str);
153log_router_exit(
void *env,
int exit_code)
177 clips_dir_ = clips_dir;
191CLIPSEnvManager::new_env(
const std::string &log_component_name)
195 struct sigaction oldact;
196 if (sigaction(SIGINT, NULL, &oldact) == 0) {
201 clips->unwatch(
"all");
203 CLIPSContextMaintainer *cm =
new CLIPSContextMaintainer(logger_, log_component_name.c_str());
205 void *env = clips->cobj();
207 SetEnvironmentContext(env, cm);
209 EnvAddRouterWithContext(env,
220 sigaction(SIGINT, &oldact, NULL);
224 throw Exception(
"CLIPS: Unable to backup "
225 "SIGINT sigaction for restoration.");
237LockPtr<CLIPS::Environment>
241 if (envs_.find(env_name) != envs_.end()) {
242 throw Exception(
"CLIPS environment '%s' already exists", env_name.c_str());
245 clips = new_env(log_component_name);
248 envs_[env_name].env = clips;
251 add_functions(env_name, clips);
254 assert_features(clips,
true);
256 guarded_load(env_name, clips_dir_ +
"utils.clp");
257 guarded_load(env_name, clips_dir_ +
"time.clp");
258 guarded_load(env_name, clips_dir_ +
"path.clp");
260 clips->evaluate(
"(path-add \"" + clips_dir_ +
"\")");
264 throw Exception(
"Failed to initialize CLIPS environment '%s'", env_name.c_str());
275 if (envs_.find(env_name) != envs_.end()) {
276 void * env = envs_[env_name].env->cobj();
277 CLIPSContextMaintainer *cm =
static_cast<CLIPSContextMaintainer *
>(GetEnvironmentContext(env));
279 EnvDeleteRouter(env, (
char *)ROUTER_NAME);
280 SetEnvironmentContext(env, NULL);
283 for (
auto feat : envs_[env_name].req_feat) {
284 if (features_.find(feat) != features_.end()) {
285 features_[feat]->clips_context_destroyed(env_name);
289 envs_.erase(env_name);
296std::map<std::string, LockPtr<CLIPS::Environment>>
299 std::map<std::string, LockPtr<CLIPS::Environment>> rv;
300 for (
auto envd : envs_) {
301 rv[envd.first] = envd.second.env;
307CLIPSEnvManager::clips_request_feature(std::string env_name, std::string feature_name)
312 "Environment %s requests feature %s",
314 feature_name.c_str());
316 if (envs_.find(env_name) == envs_.end()) {
317 logger_->
log_warn(
"ClipsEnvManager",
318 "Feature %s request from non-existent environment %s",
319 feature_name.c_str(),
321 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
323 if (features_.find(feature_name) == features_.end()) {
324 logger_->
log_warn(
"ClipsEnvManager",
325 "Environment requested unavailable feature %s",
326 feature_name.c_str());
327 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
330 ClipsEnvData &envd = envs_[env_name];
331 if (std::binary_search(envd.req_feat.begin(), envd.req_feat.end(), feature_name)) {
332 logger_->
log_warn(
"ClipsEnvManager",
333 "Environment %s requested feature %s *again*",
335 feature_name.c_str());
336 return CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL);
340 features_[feature_name]->clips_context_init(env_name, envd.env);
341 envd.req_feat.push_back(feature_name);
342 envd.req_feat.sort();
345 std::string deffacts =
"(deffacts ff-features-loaded";
347 for (
auto feat : envd.req_feat) {
348 deffacts +=
" (ff-feature-loaded " + feat +
")";
352 envd.env->assert_fact_f(
"(ff-feature-loaded %s)", feature_name.c_str());
354 if (!envd.env->build(deffacts)) {
355 logger_->
log_warn(
"ClipsEnvManager",
356 "Failed to build deffacts ff-features-loaded "
363 return CLIPS::Value(rv ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
367CLIPSEnvManager::clips_now()
371 rv.push_back(now.get_sec());
372 rv.push_back(now.get_usec());
377CLIPSEnvManager::clips_now_systime()
389CLIPSEnvManager::add_functions(
const std::string &env_name, LockPtr<CLIPS::Environment> &clips)
391 clips->add_function(
"ff-feature-request",
392 sigc::slot<CLIPS::Value, std::string>(
393 sigc::bind<0>(sigc::mem_fun(*
this, &CLIPSEnvManager::clips_request_feature),
395 clips->add_function(
"now",
396 sigc::slot<CLIPS::Values>(sigc::mem_fun(*
this, &CLIPSEnvManager::clips_now)));
397 clips->add_function(
"now-systime",
398 sigc::slot<CLIPS::Values>(
399 sigc::mem_fun(*
this, &CLIPSEnvManager::clips_now_systime)));
400 clips->add_function(
"quit", sigc::slot<void>(sigc::mem_fun(*
this, &CLIPSEnvManager::quit)));
404CLIPSEnvManager::assert_features(LockPtr<CLIPS::Environment> &clips,
bool immediate_assert)
407 std::string deffacts =
"(deffacts ff-features-available";
409 for (
auto feat : features_) {
410 deffacts +=
" (ff-feature " + feat.first +
")";
411 if (immediate_assert) {
413 clips->assert_fact_f(
"(ff-feature %s)", feat.first.c_str());
418 if (!clips->build(deffacts)) {
419 logger_->
log_warn(
"ClipsEnvManager",
"Failed to build deffacts ff-features-available");
429 for (
auto feat : features) {
430 const std::string &feature_name = feat->clips_feature_name;
432 if (features_.find(feature_name) != features_.end()) {
433 throw Exception(
"Feature '%s' has already been registered", feature_name.c_str());
436 logger_->
log_info(
"ClipsEnvManager",
"Adding feature %s", feature_name.c_str());
438 features_[feature_name] = feat;
441 for (
auto env : envs_) {
442 env.second.env.lock();
443 assert_features(env.second.env,
false);
445 env.second.env->assert_fact_f(
"(ff-feature %s)", feature_name.c_str());
446 env.second.env.unlock();
461 for (
auto feat : features) {
462 const std::string &feature_name = feat->clips_feature_name;
464 for (
auto env : envs_) {
465 if (std::binary_search(env.second.req_feat.begin(),
466 env.second.req_feat.end(),
468 throw Exception(
"Cannot remove feature %s as environment %s depends on it",
469 feature_name.c_str(),
487 for (
auto feat : features) {
488 features_.erase(feat->clips_feature_name);
493CLIPSEnvManager::guarded_load(
const std::string &env_name,
const std::string &filename)
495 if (envs_.find(env_name) == envs_.end()) {
496 throw Exception(
"guarded_load: env %s has not been registered", env_name.c_str());
499 LockPtr<CLIPS::Environment> &clips = envs_[env_name].env;
502 if ((load_rv = clips->load(filename)) != 1) {
505 throw Exception(
"%s: cannot find %s", env_name.c_str(), filename.c_str());
508 throw Exception(
"%s: CLIPS code error in %s", env_name.c_str(), filename.c_str());
514CLIPSEnvManager::quit()
516 fawkes::runtime::quit();
LockPtr< CLIPS::Environment > create_env(const std::string &env_name, const std::string &log_component_name)
Create a new environment.
std::map< std::string, LockPtr< CLIPS::Environment > > environments() const
Get map of environments.
virtual ~CLIPSEnvManager()
Destructor.
void destroy_env(const std::string &env_name)
Destroy the named environment.
CLIPSEnvManager(Logger *logger, Clock *clock, std::string &clips_dir)
Constructor.
void add_features(const std::list< CLIPSFeature * > &features)
Add a feature by name.
void remove_features(const std::list< CLIPSFeature * > &features)
Remove a feature by name.
void assert_can_remove_features(const std::list< CLIPSFeature * > &features)
Assert that a feature can be removed.
This is supposed to be the central clock in Fawkes.
Base class for exceptions in Fawkes.
virtual void log_debug(const char *component, const char *format,...)=0
Log debug message.
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
virtual void log_info(const char *component, const char *format,...)=0
Log informational message.
virtual void log(LogLevel level, const char *component, const char *format,...)
Log message of given log level.
A class for handling time.
void set_clock(Clock *clock)
Set clock for this instance.
long get_usec() const
Get microseconds.
Time & stamp_systime()
Set this time to the current system time.
long get_sec() const
Get seconds.
Fawkes library namespace.