Cumulocity using custom type properties in esper statements - cumulocity

I have a hard time using the properties of my custom types to write statements like contexts. For exemple, this is working:
create context TripContext
context PartionBySource
partition by source from EventCreated,
context ContextBorders
initiated by EventCreated(
type="c8y_SwitchPowerReport") as startEvent
terminated by EventCreated(
type="c8y_SwitchPowerReport") as endEvent;
However it's not enough and I need to check some of my custom properties to better define the context. I'd like to be able to do something like this:
create context TripContext
context PartionBySource
partition by
source,
getString(????, "customProp1"),
getNumber(????, "customProp2"),
...
from EventCreated,
context ContextBorders
initiated by EventCreated(
type="c8y_SwitchPowerReport",
getString(startEvent, "c8y_SwitchPower.newStatus") = "ON") as startEvent
terminated by EventCreated(
type="c8y_SwitchPowerReport",
getString(endEvent, "c8y_SwitchPower.newStatus") = "OFF") as endEvent;
I have no idea what to put instead of the ???? to make reference to the event. It's transparent for the "native" properties like source, time, type, etc. but as soon as there is a custom property, I have no idea how to access it.
As for the initiated/terminated syntax, there is something really weird I dont understand, but maybe it's more an Esper than Cumulocity problem. This is working:
terminated by EventCreated(
type="c8y_SwitchPowerReport",
getString(endEvent, "c8y_SwitchPower.newStatus") = "OFF") as endEvent
But this is not:
initiated by EventCreated(
type="c8y_SwitchPowerReport",
getString(startEvent, "c8y_SwitchPower.newStatus") = "ON") as startEvent
I got an error saying:
Failed to validate single-row function parameter expression 'startEvent': Property named 'startEvent' is not valid in any stream
Any insight would be appreciated.

I also couldn't find a quick way to get it run like you try.
But I would recommend the following approach. If you anyways relating heavily on custom fragments it makes sense to run the event through an additional stream that extracts this values:
create schema MyCustomEvent(
event Event,
myCustomString String,
myCustomNumber BigDecimal
);
insert into MyCustomEvent
select
e.event as Event,
getString(e, "myCustomString") as myCustomString,
getNumber(e, "myCustomNumber") as myCustomNumber
from EventCreated e
where getString(e, "myCustomString") is not null
and getNumber(e, "myCustomNumber") is not null;
Now you can easily create a context on MyCustomEvent instead on EventCreated.

Related

Removing property from operation in Cumulocity does not work?

I would like to remove a property from an operation in Cumulocity. I use the following code:
private final DeviceControlApi deviceControl;
OperationRepresentation operation = deviceControl.getOperation(new GId("some_op_id"));
operation.removeProperty("the_property_to_be_removed");
deviceControl.update(operation);
But after executing this piece of code the property is still there.
What is the right way to remove a property from operation?
The PUTs (updates) in Cumulocity IoT always do a merge on root level of the JSON so that you can do a partial update.
If you want to remove a property with your PUT request you need to explicitly to null.

Camunda : Set Assignee to all UserTasks of the process instance

I have a requirement where I need to set assignee's to all the "user-tasks" in a process instance as soon as the instance is created, which is based on the candidate group set to the user-task.
i tries getting the user-tasks using this :
Collection<UserTask> userTasks = execution.getBpmnModelInstance().getModelElementsByType(UserTask.class);
which is correct in someway but i am not able to set the assignee's , Also, looks like this would apply to the process itself and not the process instance.
secondly , I tried getting it from the taskQuery which gives me only the next task and not all the user-tasks inside a process.
Please help !!
It does not work that way. A process flow can be simplified to "a token moves through the bpmn diagram" ... only the current position of the token is relevant. So naturally, the tasklist only gives you the current task. Not what could happen after ... which you cannot know, because if you had a gateway that continues differently based on the task outcome? So drop playing with the BPMN meta model. Focus on the runtime.
You have two choices to dynamically assign user tasks:
1.) in the modeler, instead of hard-assigning the task to "a-user", use an expression like ${taskAssignment.assignTask(task)} where "taskAssignment" is a bean that provides a String method that returns the user.
2.) add a taskListener on "create" to the task and set the assignee in the listener.
for option 2 you can use the camunda spring boot events (or the (outdated) camunda-bpm-reactor extension) to register one central component rather than adding a listener to every task.

error update with where clause in DB.executeUpdate compiere

i want to update isproven to N in table m_requisition
where m_requisition_id in xx_reqverification = 'value from input'
and docstatus in xx_reqverification = 'VO'
StringBuffer s = new StringBuffer("UPDATE M_Requisition R SET")
.append(" IsProven=").append("'N'")
.append(" FROM XX_ReqVerification AS RV")
.append(" WHERE RV.DocStatus='VO'")
.append(" AND RV.XX_ReqVerification_id=")
.append(veri.getXX_ReqVerification_ID())
.append(" AND R.M_Requisition_id = RV.M_Requisition_id").append(";");
DB.executeUpdate(s.toString(), null);
but this code throw an error
DB.saveError: DBExecuteError - ERROR: syntax error at or near "where"
i am using postgresql for database
when i print s to console
UPDATE M_Requisition R SET IsProven='N'
FROM XX_ReqVerification AS RV
WHERE RV.DocStatus='VO' AND RV.XX_ReqVerification_id =1000040
AND R.M_Requisition_id = RV.M_Requisition_id;
i don't know what wrong with my code, please help me fix this.
While it's not an answer to your question specifically - see my comment/question regarding that above...
Updating the database directly like this would not be a recommended approach to customizing Adempiere. It could potentially break the consistency in the application as you would be bypassing the inbuilt mechanisms of the application such as WorkFlows, ModelValidators and perhaps Callouts. These mechanisms, along with the "Application Dictionary" exist to allow customization of the ERP application without risking inconsistencies.
If you used the inbuilt mechanisms to save an entity there would be no risk of breaking the application. Every "entity" in the application model extends a class called PO (Persistent Object) that has a save() method. Using this instead of a direct DB update would ensure all the rules defined in the Application Dictionary are followed as well as ensuring the functionalities required via the mechanisms mentioned above are run.
It should actually be an easier route with something like...
MRequisition req = new MRequistion(getCtx(), requisition_id, get_TrxName());
req.setDocStatus(DOCSTATUS_Voided);
req.setIsApproved(false);
req.save();
I can also recommend reading the following page from the wiki on extending Adempiere
One final point, there is often logic associated with a Document Status changes that it might be worth investigating too!

Grails transactions (not GORM based but using Groovy Sql)

My Grails application is not using GORM but instead uses my own SQL and DML code to read and write the database (The database is a huge normalized legacy one and this was the only viable option).
So, I use the Groovy Sql Class to do the job. The database calls are done in Services that are called in my Controllers.
Furthermore, my datasource is declared via DBCP in Tomcat - so it is not declared in Datasource.groovy.
My problem is that I need to write some transaction code, that means to open a transaction and commit after a series of successful DML calls or rollback the whole thing back in case of an error.
I thought that it would be enough to use groovy.sql.Sql#commit() and groovy.sql.Sql#rollback() respectively.
But in these methods Javadocs, the Groovy Sql documentation clearly states
If this SQL object was created from a DataSource then this method does nothing.
So, I wonder: What is the suggested way to perform transactions in my context?
Even disabling autocommit in Datasource declaration seems to be irrelevant since those two methods "...do nothing"
The Groovy Sql class has withTransaction
http://docs.groovy-lang.org/latest/html/api/groovy/sql/Sql.html#withTransaction(groovy.lang.Closure)
public void withTransaction(Closure closure)
throws java.sql.SQLException
Performs the closure within a transaction using a cached connection. If the closure takes a single argument, it will be called with the connection, otherwise it will be called with no arguments.
Give it a try.
Thanks James. I also found the following solution, reading http://grails.org/doc/latest/guide/services.html:
I declared my service as transactional
static transactional = true
This way, if an Error occurs, the previously performed DMLs will be rolled back.
For each DML statement I throw an Error describing the message. For example:
try{
sql.executeInsert("""
insert into mytable1 (col1, col2) values (${val1}, ${val2})
""")
catch(e){
throw new Error("you cant enter empty val1 or val2")
}
try{
sql.executeInsert("""
insert into mytable2 (col1, col2) values (${val1}, ${val2})
""")
catch(e){
throw new Error("you cant enter empty val1 or val2. The previous insert is rolledback!")
}
Final gotcha! The service when called from the controller, must be in a try catch, as follows:
try{
myService.myMethod(params)
}catch(e){
//http://jts-blog.com/?p=9491
Throwable t = e instanceof UndeclaredThrowableException ? e.undeclaredThrowable : e
// use t.toString() to send info to user (use in view)
// redirect / forward / render etc
}

Ninject: More than one matching bindings are available

I have a dependency with parameters constructor. When I call the action more than 1x, it show this error:
Error activating IValidationPurchaseService
More than one matching bindings are available.
Activation path:
1) Request for IValidationPurchaseService
Suggestions:
1) Ensure that you have defined a binding for IValidationPurchaseService only once.
public ActionResult Detalhes(string regionUrl, string discountUrl, DetalhesModel detalhesModel)
{
var validationPurchaseDTO = new ValidationPurchaseDTO {...}
KernelFactory.Kernel.Bind<IValidationPurchaseService>().To<ValidationPurchaseService>()
.WithConstructorArgument("validationPurchaseDTO", validationPurchaseDTO)
.WithConstructorArgument("confirmPayment", true);
this.ValidationPurchaseService = KernelFactory.Kernel.Get<IValidationPurchaseService>();
...
}
I'm not sure what are you trying to achieve by the code you cited. The error is raised because you bind the same service more than once, so when you are trying to resolve it it can't choose one (identical) binding over another. This is not how DI Container is supposed to be operated. In your example you are not getting advantage of your DI at all. You can replace your code:
KernelFactory.Kernel.Bind<IValidationPurchaseService>().To<ValidationPurchaseService>()
.WithConstructorArgument("validationPurchaseDTO", validationPurchaseDTO)
.WithConstructorArgument("confirmPayment", true);
this.ValidationPurchaseService = KernelFactory.Kernel.Get<IValidationPurchaseService>();
With this:
this.ValidationPurchaseService = new ValidationPurchaseService(validationPurchaseDTO:validationPurchaseDTO, confirmPayment:true)
If you could explain what you are trying to achieve by using ninject in this scenario the community will be able to assist further.
Your KernelFactory probably returns the same kernel (singleton) on each successive call to the controller. Which is why you add a similar binding every time you hit the URL that activates this controller. So it probably works the first time and starts failing after the second time.