I am having issues with setting up Eclipse CDT to correctly do development in C++11. It's highlighting std::error_code and honestly everything in the std namespace. While the application compiles just fine on the command line.
Screen shot included.
The full project can be found on github.com/rbaindourov/OpenWeatherMapDSLink including the hidden files used by Eclipse.
I can host the the OVA of the virtual machine if you like as well.
Thanks in advance to any industrious individual who is willing to take the time to help me configure Eclipse CDT correctly.
And apologies if my question is not to your liking.
The source for the main.cpp file originally came from:
https://github.com/CiscoDevNet/kinetic-efm-cpp-sdk/blob/master/efm-cpp-sdk-1.0.15-Ubuntu16.04-dslink-dev/examples/simple_responder/main.cpp
// #copyright_start
// Copyright (c) 2019 Cisco and/or its affiliates. All rights reserved.
// #copyright_end
#include <efm_link.h>
#include <efm_link_options.h>
#include <efm_logging.h>
#include "error_code.h"
#include <iostream>
#include <random>
#include <sstream>
/// #brief The simple responder link example demonstrates the EFM SDK API for responder implementations. Shows node,
/// action creation, and stream handling.
class SimpleResponderLink
{
public:
/// Constructs the responder link implementation.
/// #param link The link to work with.
SimpleResponderLink(cisco::efm_sdk::Link& link)
: link_(link)
, responder_(link.responder())
{
}
/// The initialize callback that will be called as soon as the initialization including serialization is complete.
/// Will create the first level node hierarchy. Only nodes not created by the deserialization will actually be
/// created.
/// #param link_name The name of the link.
/// #param ec The error code will be set to an error if the initialization failed.
void initialize(const std::string& link_name, const std::error_code& ec)
{
if (!ec) {
LOG_EFM_DEBUG(
"SimpleResponderLink", cisco::efm_sdk::DebugLevel::l1, "Responder link '" << link_name << "' initialized");
} else {
LOG_EFM_ERROR(ec, "could not initialize responder link");
}
cisco::efm_sdk::NodeBuilder builder{"/"};
builder.make_node("sdk version")
.display_name("SDK Version")
.type(cisco::efm_sdk::ValueType::String)
.value(link_.get_version_info());
builder.make_node("text")
.display_name("String")
.type(cisco::efm_sdk::ValueType::String)
.value("Hello, World!")
.writable(
cisco::efm_sdk::Writable::Write, std::bind(&::SimpleResponderLink::set_text, this, std::placeholders::_1))
.on_subscribe(std::bind(&::SimpleResponderLink::on_subscribe_text, this, std::placeholders::_1));
builder.make_node("set_text")
.display_name("Set Text")
.action(cisco::efm_sdk::Action(
cisco::efm_sdk::PermissionLevel::Read,
std::bind(
&SimpleResponderLink::set_text_called,
this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_4))
.add_param(cisco::efm_sdk::ActionParameter{"String", cisco::efm_sdk::ValueType::String})
.add_column({"Success", cisco::efm_sdk::ValueType::Bool})
.add_column({"Message", cisco::efm_sdk::ValueType::String}));
responder_.add_node(
std::move(builder),
std::bind(&SimpleResponderLink::nodes_created, this, std::placeholders::_1, std::placeholders::_2));
}
/// Callback that will be called upon construction of the first level nodes.
/// #param paths The paths of the nodes that were actually created. A path that was added to the NodeBuilder is
/// not part of the paths vector means that the node was already created. Normally, there is no need to check for
/// the presence of a path. If the error code signals no error, just continue with your work.
/// #param ec The error code will be set to an error if the node creation failed.
void nodes_created(const std::vector<cisco::efm_sdk::NodePath>& paths, const std::error_code& ec)
{
if (!ec) {
LOG_EFM_DEBUG("SimpleResponderLink", cisco::efm_sdk::DebugLevel::l1, "created nodes");
for (const auto& path : paths) {
LOG_EFM_DEBUG("SimpleResponderLink", cisco::efm_sdk::DebugLevel::l2, "created path - " << path);
}
}
}
/// Called every time the link connects to the broker.
/// Will set the value on the '/text' path.
/// #param ec The error code will be set to an error if the connect failed.
void connected(const std::error_code& ec)
{
if (!ec) {
disconnected_ = false;
LOG_EFM_INFO(responder_error_code::connected);
responder_.set_value(text_path_, cisco::efm_sdk::Variant{"Hello, World!"}, [](const std::error_code&) {});
}
}
/// Called every time the link is disconnected from the broker.
/// Will set a flag to signal the disconnected status.
/// #param ec The error code will be set to an error if the disconnect failed.
void disconnected(const std::error_code& ec)
{
LOG_EFM_INFO(responder_error_code::disconnected, ec.message());
disconnected_ = true;
}
/// Will be called the node '/text' is set via an \#set action.
/// #param value The value that was set.
void set_text(const cisco::efm_sdk::Variant& value)
{
LOG_EFM_INFO(responder_error_code::set_text, value);
}
/// Action callback for the '/set_text' action. Will set the value of the path '/text' to the given one. It will also
/// echo back the set parameter.
/// The stream will be closed automatically by the link.
/// #param stream The stream to add a result to.
/// #param parent_path The path of the node the action was called for.
/// #param params The parameters set by the peer.
/// #param ec The error code will be set to an error if the action failed.
void set_text_called(
const cisco::efm_sdk::MutableActionResultStreamPtr& stream,
const cisco::efm_sdk::NodePath& parent_path,
const cisco::efm_sdk::Variant& params,
const std::error_code& ec)
{
(void)parent_path;
if (!ec) {
LOG_EFM_DEBUG("SimpleResponderLink", cisco::efm_sdk::DebugLevel::l3, "set_text_called");
const auto* input = params.get("String");
if (input) {
auto text = *input;
responder_.set_value(text_path_, text, [stream, text](const std::error_code& ec) {
if (!ec) {
stream->set_result(cisco::efm_sdk::UniqueActionResultPtr{new cisco::efm_sdk::ActionValuesResult{
cisco::efm_sdk::ActionValuesResult(cisco::efm_sdk::ActionSuccess).add_value(true).add_value(text)}});
} else {
stream->set_result(cisco::efm_sdk::UniqueActionResultPtr{
new cisco::efm_sdk::ActionValuesResult{cisco::efm_sdk::ActionValuesResult(cisco::efm_sdk::ActionError)
.add_value(false)
.add_value("Could not set value")}});
}
});
return;
}
}
stream->set_result(cisco::efm_sdk::UniqueActionResultPtr{
new cisco::efm_sdk::ActionValuesResult{cisco::efm_sdk::ActionValuesResult(cisco::efm_sdk::ActionError)
.add_value(false)
.add_value("Could not set value")}});
}
/// Will be called if a subscribe or unsubscribe is issued for the '/text' node.
/// #param subscribe True if a subscribe was done or false if an unsubscribe was done.
void on_subscribe_text(bool subscribe)
{
if (subscribe) {
LOG_EFM_INFO(responder_error_code::subscribed_text);
} else {
LOG_EFM_INFO(responder_error_code::unsubscribed_text);
}
}
private:
cisco::efm_sdk::Link& link_;
cisco::efm_sdk::Responder& responder_;
cisco::efm_sdk::NodePath text_path_{"/text"};
bool disconnected_{true};
};
int main(int argc, char* argv[])
{
cisco::efm_sdk::FileConfigLoader loader;
cisco::efm_sdk::LinkOptions options("Simple-Responder-Link", loader);
if (!options.parse(argc, argv, std::cerr)) {
return EXIT_FAILURE;
}
cisco::efm_sdk::Link link(std::move(options), cisco::efm_sdk::LinkType::Responder);
LOG_EFM_INFO(::responder_error_code::build_with_version, link.get_version_info());
SimpleResponderLink responder_link(link);
link.set_on_initialized_handler(
std::bind(&SimpleResponderLink::initialize, &responder_link, std::placeholders::_1, std::placeholders::_2));
link.set_on_connected_handler(std::bind(&SimpleResponderLink::connected, &responder_link, std::placeholders::_1));
link.set_on_disconnected_handler(
std::bind(&SimpleResponderLink::disconnected, &responder_link, std::placeholders::_1));
link.run();
return EXIT_SUCCESS;
}
Related
I am trying to read data with unkown size using UART Receive Interrupt. In the call back function, I enabled Rx interrupt in order to read characters until \n is gotten. If \n is get, then higher priority task which is deferred interrupt handler is woken. The problem is that I tried to read one by one byte via call back function and I tried to put each character into a buffer, but unfortunately buffer could not get any character. Moreover, deferred interrupt handler could not be woken.
My STM32 board is STM32F767ZI, and my IDE is KEIL.
Some Important notes before sharing the code:
1. rxIndex and gpsBuffer are declared as global.
2. Periodic function works without any problem.
Here is my code:
Periodic Function, Priority = 1
void vPeriodicTask(void *pvParameters)
{
const TickType_t xDelay500ms = pdMS_TO_TICKS(500UL);
while (1) {
vTaskDelay(xDelay500ms);
HAL_UART_Transmit(&huart3,(uint8_t*)"Imu\r\n",sizeof("Imu\r\n"),1000);
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_7);
}
}
Deferred Interrupt, Priority = 3
void vHandlerTask(void *pvParameters)
{
const TickType_t xMaxExpectedBlockTime = pdMS_TO_TICKS(1000);
while(1) {
if (xSemaphoreTake(xBinarySemaphore,xMaxExpectedBlockTime) == pdPASS) {
HAL_UART_Transmit(&huart3,(uint8_t*)"Semaphore Acquired\r\n",sizeof("Semaphore
Acquired\r\n"),1000);
// Some important processes will be added here
rxIndex = 0;
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_14);
}
}
}
Call back function:
void HAL_UART_RxCptlCallBack(UART_HandleTypeDef *huart)
{
gpsBuffer[rxIndex++] = rData;
if (rData == 0x0A) {
BaseType_t xHigherPriorityTaskWoken;
xSemaphoreGiveFromISR(xBinarySemaphore,&xHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
HAL_UART_Receive_IT(huart,(uint8_t*)&rData,1);
}
Main function
HAL_UART_Receive_IT(&huart3,&rData,1);
xBinarySemaphore = xSemaphoreCreateBinary();
if (xBinarySemaphore != NULL) {
//success
xTaskCreate(vHandlerTask,"Handler",128,NULL,1,&vHandlerTaskHandler);
xTaskCreate(vPeriodicTask,"Periodic",128,NULL,3,&vPeriodicTaskHandler);
vTaskStartScheduler();
}
Using HAL for it is a best way to get into the troubles. It uses HAL_Delay which is systick dependant and you should rewrite this function to read RTOS tick instead.
I use queues to pass the data (the references to data) but it should work. There is always a big question mark when using the HAL functions.
void HAL_UART_RxCptlCallBack(UART_HandleTypeDef *huart)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
gpsBuffer[rxIndex++] = rData;
if (rData == 0x0A) {
if(xSemaphoreGiveFromISR(xBinarySemaphore,&xHigherPriorityTaskWoken) == pdFALSE)
{
/* some error handling */
}
}
HAL_UART_Receive_IT(huart,(uint8_t*)&rData,1);
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
Concluding if I use HAL & RTOS I always modify the way HAL handles timeouts.
I'm new in learning about how PostSharp works. I've written some code using NLog that I want to improve using PostSharp.
The Nlog output is working (output is done both on console & file).
The PostSharp isn't working at all (no output to file, no output console).
I tried to follow to documentation from PostSharp website : https://doc.postsharp.net/nlog
I don't understand where my mistake is :(
Can somebody give me a little hand to solve this problem ?
Thanks for help.
using System;
using PostSharp.Patterns.Diagnostics;
using PostSharp.Patterns.Diagnostics.Backends.NLog;
using NLog.Config;
using NLog.Targets;
using System.Text;
using NLog;
using LogLevel = PostSharp.Patterns.Diagnostics.LogLevel;
using static PostSharp.Patterns.Diagnostics.FormattedMessageBuilder;
namespace MyNameSpace
{
static class LogSources
{
// Configure a prototype LogSource that you will reuse in several classes.
public static readonly LogSource Default = LogSource.Get().WithLevels(LogLevel.Trace, LogLevel.Warning);
}
/// <summary>
/// Main class
/// </summary>
[Log]
class Program
{
static LoggingConfiguration config;
static readonly LogSource logSource = LogSource.Get().WithLevels(LogLevel.Trace, LogLevel.Warning);
/// <summary>
/// MAIN ENTRY
/// </summary>
static void Main()
{
InitNLog(Environment.ExpandEnvironmentVariables (#"%TEMP%\MyLog.txt"));
InitPostSharp();
LogMe();
logSource.Default.Write (Formatted("This is a TEST message"));
NLog.LogManager.GetCurrentClassLogger().Trace("This is a Trace message");
NLog.LogManager.GetCurrentClassLogger().Debug("This is a Debug message");
NLog.LogManager.GetCurrentClassLogger().Info("This is an Info message");
NLog.LogManager.GetCurrentClassLogger().Warn("This is a Warn message");
NLog.LogManager.GetCurrentClassLogger().Error("This is an Error message");
NLog.LogManager.GetCurrentClassLogger().Fatal("This is a Fatal error message");
Console.ReadKey();
}
[Log]
public static void LogMe()
{
logSource.Default.Write(Formatted("pleassseee loggggg meeeee"));
}
/// <summary>
/// Initializes PostSharp.
/// </summary>
private static void InitPostSharp()
{
LoggingServices.DefaultBackend = new NLogLoggingBackend(new LogFactory(config));
}
/// <summary>
/// Init NLog system
/// </summary>
/// <param name="outputFileName">Full path for output logging file.</param>
static void InitNLog(string outputFileName)
{
// NLOG CONFIGURATION - https://github.com/NLog/NLog/wiki/Tutorial
// Step 1. Create configuration object
config = new LoggingConfiguration();
// Step 2. Create targets and add them to the configuration
ColoredConsoleTarget consoleTarget = new ColoredConsoleTarget();
consoleTarget.Layout = #"${date:universalTime=true:format=HH\:mm\:ss.fff} ${message} ${exception:format=Message}";
consoleTarget.UseDefaultRowHighlightingRules = false;
consoleTarget.RowHighlightingRules.Clear();
consoleTarget.RowHighlightingRules.Add(new ConsoleRowHighlightingRule("level == LogLevel.Trace and starts-with('${message}','[THREAD:')", ConsoleOutputColor.Cyan, ConsoleOutputColor.Black));
consoleTarget.RowHighlightingRules.Add(new ConsoleRowHighlightingRule("level == LogLevel.Trace", ConsoleOutputColor.DarkCyan, ConsoleOutputColor.Black));
consoleTarget.RowHighlightingRules.Add(new ConsoleRowHighlightingRule("level == LogLevel.Debug", ConsoleOutputColor.DarkGray, ConsoleOutputColor.Black));
consoleTarget.RowHighlightingRules.Add(new ConsoleRowHighlightingRule("level == LogLevel.Info", ConsoleOutputColor.White, ConsoleOutputColor.Black));
consoleTarget.RowHighlightingRules.Add(new ConsoleRowHighlightingRule("level == LogLevel.Warn", ConsoleOutputColor.Yellow, ConsoleOutputColor.Black));
consoleTarget.RowHighlightingRules.Add(new ConsoleRowHighlightingRule("level == LogLevel.Error", ConsoleOutputColor.Red, ConsoleOutputColor.Black));
consoleTarget.RowHighlightingRules.Add(new ConsoleRowHighlightingRule("level >= LogLevel.Fatal", ConsoleOutputColor.White, ConsoleOutputColor.DarkRed));
consoleTarget.Encoding = Encoding.Unicode;
config.AddTarget("console", consoleTarget);
FileTarget fileTarget = new FileTarget();
config.AddTarget("file", fileTarget);
fileTarget.FileName = outputFileName;
// Step 3. Set target properties
consoleTarget.Layout = "${logger}|${message}";
fileTarget.Layout = "${machinename}|${longdate}|${logger}|${level:uppercase=true}|${message}|${exception:separator=\r\n:format=message,type,method,stackTrace:maxInnerExceptionLevel=10:innerExceptionSeparator=\r\n:innerFormat=message,type,method,stackTrace}";
// Step 4. Define rules
config.LoggingRules.Add(new LoggingRule("*", NLog.LogLevel.Trace, consoleTarget));
config.LoggingRules.Add(new LoggingRule("*", NLog.LogLevel.Trace, fileTarget));
// Step 5. Activate the configuration
LogManager.Configuration = config;
LogManager.EnableLogging();
}
}
}
PostSharp only logs methods annotated with [Log] and it only starts logging after you set the backend, which you did in InitPostSharp.
If you add to your class Program the following method:
[Log]
public static void LogMe()
{
}
and call LogMe() from Main after InitPostSharp, it will be logged into NLog.
A problem with your code is also this line:
[Log(AttributeExclude=true)] which means "remove logging" (because of the AttributeExclude). If you instead use simply [Log], the attribute will multicast down on all methods of the class, including LogMe. Still, methods calls that started before you set up the backend in InitPostSharp will not be affected.
I'm trying to connect a VTKcallback to a Qt slot, so the slot will be fired when the callback happens.
I'm using a QVTKWidget to render a point cloud that has been added into a PCLVisualizer (from the point cloud library, PCL).
Let's show some code:
PointCloud.h
class PointCloud: public QObject {
Q_OBJECT
private:
static void loadStartCallback(
vtkObject *caller,
unsigned long eventId,
void *clientData,
void *callData
);
static void loadEndCallback(
vtkObject *caller,
unsigned long eventId,
void *clientData,
void *callData
);
void load(void);
// more funcs and methods
private:
QVTKWidget* widget;
pcl::visualization::PCLVisualizer* visualizer;
unsinged long observerStartTag;
unsinged long observerEndTag;
// more attributes
}
PointCloud.cpp
void PointCloud::loadStartCallback(
vtkObject* caller,
unsigned long eventId,
void* clientData,
void* callData
) {
qDebug() << "\t\tPointCloud - loadCallback started\n";
if(clientData) {
PointCloud* self = reinterpret_cast<PointCloud*>( clientData );
self->widget->GetRenderWindow()->RemoveObserver(self->observerStartTag);
}
void PointCloud::loadEndCallback(
vtkObject* caller,
unsigned long eventId,
void* clientData,
void* callData
) {
qDebug() << "\t\tPointCloud - loadCallback ended\n";
if(clientData) {
PointCloud* self = reinterpret_cast<PointCloud*>( clientData );
self->widget->GetRenderWindow()->RemoveObserver(self->observerEndTag);
}
}
void load(void) {
vtkSmartPointer<vtkRenderWindow> renderWindow = visualizer->getRenderWindow();
vtkSmartPointer<vtkCallbackCommand> startCallback = vtkSmartPointer<vtkCallbackCommand>::New();
startCallback->SetCallback( loadStartCallback );
startCallback->SetClientData(this);
observerStartTag = renderWindow->AddObserver(vtkCommand::StartEvent, startCallback );
vtkSmartPointer<vtkCallbackCommand> endCallback = vtkSmartPointer<vtkCallbackCommand>::New();
endCallback->SetCallback( loadEndCallback );
endCallback->SetClientData(this);
observerEndTag = renderWindow->AddObserver(vtkCommand::EndEvent, endCallback );
// more processing. local_cloud is already populated
// and functional at this point
widget->SetRenderWindow( renderWindow );
visualizer->addPointCloud<pcl::PointXYZ>(local_cloud, "local_cloud");
widget->Show();
widget->Update();
}
This works well, once the cloud rendering starts, the PointCloud - loadCallback started is printed and when the rendering has ended and the cloud is shown, the message PointCloud - loadCallback ended is printed.
Now, besides printing the end message, I want to fire a Qt slot as well. I'm trying to use the vtkEventQtSlotConnect class for that, as it seems that is the right choice for connecting callbacks to slots:
New in PointCloud.h
private slots:
void test(void);
New in PointCloud.cpp
void PointCloud::test(void) { qDebug() << "\t\tThis is a test\n; }
Added into PointCloud::load(), before calling visualizer->addPointCloud
vtkEventQtSlotConnect* vtk_qt_connector = vtkEventQtSlotConnect::New();
vtk_qt_connector->Connect(
renderWindow,
vtkCommand::EndEvent,
this,
SLOT(test(void)),
0,
1.0
);
// AFTER widget->Update()
vtk_qt_connector->Disconnect(); // NO PARAM: disconnects ALL slots
vtk_qt_connector->Delete();
} // End of PointCloud::load()
With those additions, the messages in the callbacks are printed, but the message inside the test() slot is never shown.
Any idea of what I'm doing wrong?
EDIT
In the VTKexamples for callbacks that I've seen, a vtkRendeWindowInteractor is used to manage the callbacks. However, If I add the callback observer to it, it is not as accurate as adding them to the render window directly.
Ok,
I have checked again the code and found something new. Some co-worker has added a QThread in the load() method to smooth things, but forgot to document/tell that there was a QThreadthere.
In PointCloud::load()
QThread* thread = new QThread;
ThreadedCloud* tcloud = new ThreadedCloud; // computes internal vars and more
tcloud->moveToThread(thread);
connect(thread, SIGNAL(started()), tcloud, SLOT(read()), Qt::QueuedConnection );
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()), Qt::QueuedConnection );
connect(tcloud, SIGNAL(cloudIsLoaded()), this, SLOT(addCloudToViewer()), Qt::QueuedConnection );
connect(tcloud, SIGNAL(cloudIsLoaded()), thread, SLOT(quit()), Qt::QueuedConnection );
connect(tcloud, SIGNAL(cloudIsLoaded()), tcloud, SLOT(deleteLater()), Qt::QueuedConnection );
connect(tcloud, SIGNAL(cloudIsNotLoaded(std::string)), this, SLOT(errorLoadingCloud(std::string)), Qt::QueuedConnection );
thread->start();
The cloudIsLoaded() is a signal that is emitted when the thread has finished whatever it has to do and we're ready to add the cloud to the PCLVisualizer and render it. That is done in addCloudToViewer.
The key factor here is that once the thread is started, the control flow exits the load()method and because I'm disconnecting the callback/slot before the end of the method, once the cloud is being rendererd that connection isn't there anymore!
So the solution was to move the vtk_qt_connector inside the addCloudToViewer method and do there the callback/slot connection.
Ciao, I have tested in several ways, but I'm still unable to test and verify the Event expiration mechanism in Drools Fusion, so I'm looking for some little guidance, please?
I've read the manual and I'm interested in this feature:
In other words, one an event is inserted into the working memory, it is possible for the engine to find out when an event can no longer match other facts and automatically retract it, releasing its associated resources.
I'm using the Drools IDE in Eclipse, 5.4.0.Final and I modified the template code created by the "New Drools Project" wizard to test and verify for Event expiration.
The code below. The way I understood to make the "lifecycle" to work correctly is that:
You must setup the KBase in STREAM mode - check
You must Insert the Events in temporal order - check
You must define temporal constraints between Events - check in my case is last Message()
However, when I inspect the EventFactHandle at the end, none of the Event() has expired.
Thanks for your help.
Java:
public class DroolsTest {
public static final void main(String[] args) {
try {
KnowledgeBase kbase = readKnowledgeBase();
// I do want the pseudo clock
KnowledgeSessionConfiguration conf = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
conf.setOption(ClockTypeOption.get("pseudo"));
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession(conf, null);
SessionPseudoClock clock = ksession.getSessionClock();
KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");
// Insert of 2 Event:
Message message = new Message();
message.setMessage("Message 1");
message.setStatus(Message.HELLO);
ksession.insert(message);
ksession.fireAllRules();
clock.advanceTime(1, TimeUnit.DAYS);
Message message2 = new Message();
message2.setMessage("Message 2");
message2.setStatus(Message.HELLO);
ksession.insert(message2);
ksession.fireAllRules();
clock.advanceTime(1, TimeUnit.DAYS);
ksession.fireAllRules();
// Now I do check what I have in the working memory and if EventFactHandle if it's expired or not:
for (FactHandle f : ksession.getFactHandles()) {
if (f instanceof EventFactHandle) {
System.out.println(((EventFactHandle)f)+" "+((EventFactHandle)f).isExpired());
} else {
System.out.println("not an Event: "+f);
}
}
logger.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
private static KnowledgeBase readKnowledgeBase() throws Exception {
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("Sample.drl"), ResourceType.DRL);
KnowledgeBuilderErrors errors = kbuilder.getErrors();
if (errors.size() > 0) {
for (KnowledgeBuilderError error: errors) {
System.err.println(error);
}
throw new IllegalArgumentException("Could not parse knowledge.");
}
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
// following 2 lines is the template code modified for STREAM configuration
KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( EventProcessingOption.STREAM );
return kbase;
}
/*
* This is OK from template, as from the doc:
* By default, the timestamp for a given event is read from the Session Clock and assigned to the event at the time the event is inserted into the working memory.
*/
public static class Message {
public static final int HELLO = 0;
public static final int GOODBYE = 1;
private String message;
private int status;
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
public int getStatus() {
return this.status;
}
public void setStatus(int status) {
this.status = status;
}
}
}
Drools:
package com.sample
import com.sample.DroolsTest.Message;
declare Message
#role(event)
end
declare window LastMessageWindow
Message() over window:length(1)
end
rule "Hello World"
when
accumulate( $m : Message(status==Message.HELLO) from window LastMessageWindow,
$messages : collectList( $m ) )
then
System.out.println( ((Message)$messages.get(0)).getMessage() );
end
Please note: even if I add expiration of 1second to the Message event, by
#expires(1s)
I still don't get the expected result that the very first Message event inserted, I would have expected is now expired? Thanks for your help.
Found solution! Obviously it was me being stupid and not realizing I was using Drools 5.4.0.Final while still referring to old documentation of 5.2.0.Final. In the updated documentation for Drools Fusion 5.4.0.Final, this box is added for 2.6.2. Sliding Length Windows:
Please note that length based windows do not define temporal constraints for event expiration from the session, and the engine will not consider them. If events have no other rules defining temporal constraints and no explicit expiration policy, the engine will keep them in the session indefinitely.
Therefore the 3rd requirement I originally enlisted of "You must define temporal constraints between Events" is obviously NOT met because I now understand Sliding Length Window in Drools 5.4.0.Final:
Message() over window:length(1)
are indeed NOT a definition of a temporal constraints for event expiration from the session.
Updating this answer hopefully somebody will find it helpful. Also, just so for your know, me being stupid actually for relying on googling in order to reach the doc, and sometimes you don't get redirected to the current release documentation, so it seems...
Can you please tell me if there is any example for using GIO Server Socket
(the one which I can open a port and listen on socket requests)?
I would like to use it to 'remote-control' my GTK+ application.
I think you should do something like this:
#define MY_PORT 47110
/* Listener callback, this gets called by GTK+ when
* there's socket activity to handle.
*/
static gboolean cb_listener(GIOChannel *source, GIOCondition condition, gpointer data
{
switch(condition)
{
case G_IO_IN:
/* There's data to be read. */
break;
default:
/* An error has occured, or socket is closed. */
return FALSE; /* This tells GIO to remove the source, might be drastic. */
}
return TRUE; /* This tells GIO that all is fine. */
}
Then elsewhere (in a function, maybe main()):
GSocketListener *listener;
listener = g_socket_listener_new();
g_socket_listener_add_inet_port(listener, MY_PORT, NULL, NULL);
g_io_add_watch(G_IO_CHANNEL(listener), G_IO_IN | G_IO_ERR | G_IO_HUP, cb_listener, NULL);