How to get a Fact creating BRL in Guvnor and querying Drools Server - drools

I'm stuck with BRL rules in Guvnor.. I'm trying to execute rules from my application using Drools Server (this solution because in production I can use more server and maybe improve performance.. Not sure about this as it's the first time that in my company we are using Drools)..
So basically the rule is .. Given an object Route setting the property "selectedOutboundJourney" that I uploaded in guvnor in a jar, I'd like to get another object with the property "selectedReturnJourney" set.. (but Is it possible to get the same object??)
Actually I get a Route object where the selectedReturnJourney is null.
I'm not sure if using BRL is a good solution given the troubles that I'm having.. It seems easy to use for non technical people that may want to change the rules or creating new ones.
Anyway..
This is the BRL that I created in Guvnor:
rule "Selected Return for Dover - Calais"
dialect "mvel"
when
Route( selectedOutboundJourney == "DOCA" )
then
Route fact0 = new Route();
fact0.setSelectedReturnJourney( "CADO" );
insertLogical( fact0 );
end
This is the code I'm using:
final List<Command> commands = new ArrayList<Command>();
final Command insertObjectCommand = CommandFactory.newInsert(input, RESULT, true, "default");
final Command getObjectCommand = CommandFactory.newGetObjects();
final Command fireAllRulesCommand = CommandFactory.newFireAllRules();
commands.add(insertObjectCommand);
commands.add(getObjectCommand);
commands.add(fireAllRulesCommand);
final ExecutionResults executionResults = droolsHttpClient.callDroolsServer(commands);
return executionResults.getValue(RESULT);
The class DroolsHttpClient is:
public ExecutionResults callDroolsServer(final List<Command> commands) throws DroolsException
{
PostMethod postMethod = null;
try
{
final HttpClient httpClient = new HttpClient();
final String droolsServerHost = Config.getString(PoferriesrulesengineConstants.DROOLS_SERVER_HOST, "");
final int droolsServerPort = Config.getInt(PoferriesrulesengineConstants.DROOLS_SERVER_PORT, 0);
httpClient.getHostConfiguration().setHost(droolsServerHost, droolsServerPort);
final String droolsServerUrl = Config.getString(PoferriesrulesengineConstants.DROOLS_SERVER_URL, "");
postMethod = new PostMethod(droolsServerUrl);
final BatchExecutionCommand command = CommandFactory.newBatchExecution(commands, PoferriesrulesengineConstants.DROOLS_SESSION);
final XStream xStreamMarshaller = BatchExecutionHelper.newXStreamMarshaller();
final String xmlCommand = xStreamMarshaller.toXML(command);
final StringRequestEntity request = new StringRequestEntity(xmlCommand, MediaType.TEXT_PLAIN_VALUE, CharEncoding.UTF_8);
postMethod.setRequestEntity(request);
httpClient.executeMethod(postMethod);
if (postMethod.getStatusCode() != 200)
{
throw new RuntimeException("Drools Communication Error, code: " + postMethod.getStatusCode());
}
final String response = postMethod.getResponseBodyAsString();
final ExecutionResults executionResults = (ExecutionResults) xStreamMarshaller.fromXML(response);
return executionResults;
}
catch (final Exception e)
{
throw new DroolsException(e.getMessage());
}
finally
{
postMethod.releaseConnection();
}
}
If I use a DRL like below it words perfectly without using the getObjectCommand:
rule "Selected Return Routes for Dover Calais"
when
r : Route(selectedOutboundJourney == "DOCA")
then
r.setSelectedReturnJourney("CADO")
end
Can anyone help me out, please?

Assuming you only have one fact in your Knowledge Session at the start, after the execution of the following rule
rule "Selected Return for Dover - Calais"
dialect "mvel"
when
Route( selectedOutboundJourney == "DOCA" )
then
Route fact0 = new Route()
fact0.setSelectedReturnJourney( "CADO" )
insert( fact0 )
end
you will have two Route facts in your session, since you just have inserted the second one.
Route: selectedOutboundJourney = "DOCA", selectedReturnJourney=null
Route: selectedOutboundJourney = null, selectedReturnJourney="DACO"
If you want to modify the original fact use the following rule:
rule "Selected Return Routes for Dover Calais"
when
$r : Route(selectedOutboundJourney == "DOCA")
then
modify ($r) {
selectedReturnJourney = "CADO"
}
end

Related

Hapi Fhir query with AND / OR with map

Using Hapi Fhir, I try to write a query to use a map to pass in where condition, as follow:
Map<String, List<IQueryParameterType>> hmParameter = criteria.getMapForWhere();
Bundle bundle = fhirClientR4Configuration.clientFhihrR4().search().forResource(ServiceRequest.class)
.where(hmParameter).returnBundle(Bundle.class).execute();
My criteria object has a method getMapForWhere() where I populate this map with information inside my wrapper front end object as follow:
public Map<String, List<IQueryParameterType>> getMapForWhere() {
Map<String, List<IQueryParameterType>> hmOut = new HashMap<String, List<IQueryParameterType>>();
// Adding STATUS
if (this.status != null && !this.status.equals("")) {
StringParam sp = new StringParam();
sp.setValue(this.status);
List<IQueryParameterType> lst = new ArrayList<IQueryParameterType>();
lst.add(sp);
hmOut.put(ServiceRequest.SP_STATUS, lst);
}
// Adding INTENT
if (this.intent != null && !this.intent.equals("")) {
StringParam sp = new StringParam();
sp.setValue(this.intent);
List<IQueryParameterType> lst = new ArrayList<IQueryParameterType>();
lst.add(sp);
hmOut.put(ServiceRequest.SP_INTENT, lst);
}
return hmOut;
}
This code works fine when I want to wirte a query with all AND.
But if I want to add another condition as follow:
List<IQueryParameterOr> lstOr = new ArrayList<IQueryParameterOr>();
StringOrListParam lstServices = new StringOrListParam();
StringParam sp = new StringParam();
StringParam sg = new StringParam();
sp.setValue(MEDICAL_SERVICE_PAI);
sg.setValue(SOCIAL_SERVICE_PAI);
lstServices.addOr(sp);
lstServices.addOr(sg);
lstOr.add(lstServices);
hmOut.put(ServiceRequest.SP_CATEGORY, lstOr);
Obviously hmOut goes in error because definition of that map is different. But I don't know how to convert IParameterOr with IParameterType.

Using a Beakerx Custom Magic

I've created a custom Magic command with the intention of generating a spark query programatically. Here's the relevant part of my class that implements the MagicCommandFunctionality:
MagicCommandOutcomeItem execute(MagicCommandExecutionParam magicCommandExecutionParam) {
// get the string that was entered:
String input = magicCommandExecutionParam.command.substring(MAGIC.length())
// use the input to generate a query
String generatedQuery = Interpreter.interpret(input)
MIMEContainer result = Text(generatedQuery);
return new MagicCommandOutput(MagicCommandOutcomeItem.Status.OK, result.getData().toString());
}
This works splendidly. It returns the command that I generated. (As text)
My question is -- how do I coerce the notebook into evaluating that value in the cell? My guess is that a SimpleEvaluationObject and TryResult are involved, but I can't find any examples of their use
Rather than creating the MagicCommandOutput I probably want the Kernel to create one for me. I see that the KernelMagicCommand has an execute method that would do that. Anyone have any ideas?
Okay, I found one way to do it. Here's my solution:
You can ask the current kernelManager for the kernel you're interested in,
then call PythonEntryPoint.evaluate. It seems to do the job!
#Override
MagicCommandOutcomeItem execute(MagicCommandExecutionParam magicCommandExecutionParam) {
String input = magicCommandExecutionParam.command.substring(MAGIC.length() + 1)
// this is the Scala code I want to evaluate:
String codeToExecute = <your code here>
KernelFunctionality kernel = KernelManager.get()
PythonEntryPoint pep = kernel.getPythonEntryPoint(SCALA_KERNEL)
pep.evaluate(codeToExecute)
pep.getShellMsg()
List<Message> messages = new ArrayList<>()
//until there are messages on iopub channel available collect them into response
while (true) {
String iopubMsg = pep.getIopubMsg()
if (iopubMsg == "null") break
try {
Message msg = parseMessage(iopubMsg) //(I didn't show this part)
messages.add(msg)
String commId = (String) msg.getContent().get("comm_id")
if (commId != null) {
kernel.addCommIdManagerMapping(commId, SCALA_KERNEL)
}
} catch (IOException e) {
log.error("There was an error: ${e.getMessage()}")
return new MagicKernelResponse(MagicCommandOutcomeItem.Status.ERROR, messages)
}
}
return new MagicKernelResponse(MagicCommandOutcomeItem.Status.OK, messages)
}

OPC UA.NET custom Node Manager creating

I'm trying to use UA-.NETStandardLibrary by OPC Foundation to create my own OPC UA Server that will maintain some variables.
I've created a server class inherited from StandardServer and node manager inherited from CustomNodeManager2.
There were some node managers in their examples, I removed them and add my own one. The server starts normally and doesn't contain any nodes except from standard ones, as planned. So, my problem is how to create my own variable node from code (not from xml, as in examples) and be able update its value on demand.
For example, I want to add a folder with couple of nodes inside.
Does anyone have a code snippet which demonstrates how to do it? I don't want anybody write it for me, I will appreciate only if you just tell me about a right way to make it.
Thanks a lot.
I am pretty sure the snippets you are looking for are included. Here is my testing code and I am 100% positive, I didn't write the second piece of code. Anyway, if this helps you...
{
var ticker_seq = createVariable(myFolder, "MyFolder/Ticker", "Ticker", BuiltInType.UInt64, ValueRanks.Scalar);
variables.Add(ticker_seq);
subscriptions.Add(clock.Ticker.Subscribe(val =>
{
lock (Lock)
{
ticker_seq.Value = val;
ticker_seq.Timestamp = DateTime.UtcNow;
ticker_seq.ClearChangeMasks(SystemContext, false);
}
}));
}
and creation
private BaseDataVariableState createVariable(NodeState parent, string path, string name, NodeId dataType, int valueRank)
{
BaseDataVariableState variable = new BaseDataVariableState(parent);
variable.SymbolicName = name;
variable.ReferenceTypeId = ReferenceTypes.Organizes;
variable.TypeDefinitionId = VariableTypeIds.BaseDataVariableType;
variable.NodeId = new NodeId(path, NamespaceIndex);
variable.BrowseName = new QualifiedName(path, NamespaceIndex);
variable.DisplayName = new LocalizedText("en", name);
variable.WriteMask = AttributeWriteMask.DisplayName | AttributeWriteMask.Description;
variable.UserWriteMask = AttributeWriteMask.DisplayName | AttributeWriteMask.Description;
variable.DataType = dataType;
variable.ValueRank = valueRank;
variable.AccessLevel = AccessLevels.CurrentReadOrWrite;
variable.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
variable.Historizing = false;
variable.Value = 0;
variable.StatusCode = StatusCodes.Good;
variable.Timestamp = DateTime.UtcNow;
if (parent != null)
{
parent.AddChild(variable);
}
return variable;
}
creating the folder:
private FolderState CreateFolder(NodeState parent, string path, string name)
{
FolderState folder = new FolderState(parent);
folder.SymbolicName = name;
folder.ReferenceTypeId = ReferenceTypes.Organizes;
folder.TypeDefinitionId = ObjectTypeIds.FolderType;
folder.NodeId = new NodeId(path, NamespaceIndex);
folder.BrowseName = new QualifiedName(path, NamespaceIndex);
folder.DisplayName = new LocalizedText("en", name);
folder.WriteMask = AttributeWriteMask.None;
folder.UserWriteMask = AttributeWriteMask.None;
folder.EventNotifier = EventNotifiers.None;
if (parent != null)
{
parent.AddChild(folder);
}
return folder;
}

How to force the Plugin on Post-Operation to Submit?

I have a plugin in post-operation witch need to create a folder on sharepoint via webservice, to do that, my plugin calls a webservice to execute a FechXML to get the info from the entity, but the problem is that entity still not exist, and it give me Null.
How do i force the plugin to submit/save the data to my FechXml to work?
PLUGIN CODE:
try
{
Entity entity;
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
entity = (Entity)context.InputParameters["Target"];
if (entity.LogicalName != "fcg_processos")
{
throw new InvalidPluginExecutionException("Ocorreu um erro no PlugIn Create Folder.");
}
}
else
{
throw new InvalidPluginExecutionException("Ocorreu um erro no PlugIn Create Folder.");
}
processosid = (Guid)((Entity)context.InputParameters["Target"])["fcg_processosid"];
string processoid2 = processosid.ToString();
PluginSharepointProcessos.ServiceReference.PrxActivityResult result = log.CreateFolderSP("Processo", processoid2);
string resultado = result.xmlContent;
if (result.retCode > 0)
{
throw new InvalidPluginExecutionException("Ocorreu um erro na criação do Folder do Processo.");
}
WEBSERVICE CODE:
{
//WEBSERVICE TO CALL XML FROM ENTITY
PrxActivityResult Processo = ProcessoFetch2("", "", guid);
string stxml;
stxml = Processo.XmlContent;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(stxml);
XmlNodeList nodeList = xmlDoc.SelectNodes("resultset/result");
List<string[]> lista = new List<string[]>();
string[] strs = new string[7];
if (nodeList.Count != 0)//verificar o numero de registos
{
foreach (XmlNode xmlnode in nodeList)
{
if (xmlnode.SelectSingleNode("//fcg_numero") != null)
strs[2] = xmlnode.SelectSingleNode("//fcg_numero").InnerText;
else
strs[2] = "";
if (xmlnode.SelectSingleNode("//Concurso.fcg_numero") != null)
strs[3] = xmlnode.SelectSingleNode("//Concurso.fcg_numero").InnerText;
else
strs[3] = "";
}
}
IwsspClient FmwSharepoint = new IwsspClient();
PrxActivityResult folderresult = new PrxActivityResult();
List<ws.fcg.sipp.svc.ServiceReferenceSharePoint.PareChave> arrayfields = new List<ws.fcg.sipp.svc.ServiceReferenceSharePoint.PareChave>();
ws.fcg.sipp.svc.ServiceReferenceSharePoint.PareChave nprocesso = new ws.fcg.sipp.svc.ServiceReferenceSharePoint.PareChave();
nprocesso.Key = "FCG_Numero_Processo";
nprocesso.value = strs[2];
arrayfields.Add(nprocesso);
ws.fcg.sipp.svc.ServiceReferenceSharePoint.PareChave npconcurso = new ws.fcg.sipp.svc.ServiceReferenceSharePoint.PareChave();
npconcurso.Key = "FCG_Numero_Concurso";
npconcurso.value = strs[3];
arrayfields.Add(npconcurso);
ws.fcg.sipp.svc.ServiceReferenceSharePoint.PareChave npguid = new ws.fcg.sipp.svc.ServiceReferenceSharePoint.PareChave();
npguid.Key = "FCG_Guid_CRM";
npguid.value = guid;
arrayfields.Add(npguid);
folderresult = FmwSharepoint.CreateFolder("http://localhost/folder", "Processos", strs[2], arrayfields.ToArray());
res = folderresult;
}
When a plugin runs on the Post-Operation, it is still within the database transaction, and it hasn't actually been committed to the database. Any calls done with the service reference passed in as a part of the Plugin Context will be executed within the context on the database transaction and you will be able to retrieve the newly created/updated values. If you create a brand new OrganizationServiceProxy (Which I'm guessing is what you're doing), it will execute outside of the database transaction, and will not see the newly created / updated values.
As #AndyMeyers suggests in his comment (which really should be an answer IMHO), grabbing the data from the plugin context either via a pre/post image or the target is ideal since it eliminates another database call. If you're having to lookup records that may have been created by another plugin that fired earlier, you'll need to use the IOrganizationService that is included in the plugin context.
I had no option and I used this code to run webservice based on image and forget the FecthXml, as mentioned, i get all info from the Image on the post operation and send back to the WebService. Thanks, here is the code:
entity = (Entity)context.InputParameters["Target"];
concursid = (Guid)entity.Attributes["fcg_concursid"];
guid = concursid.ToString();
string npconcurs = (string)entity.Attributes["fcg_numer"];
nconcurs= npconcurs;
EntityReference nprograma = (EntityReference)entity.Attributes["fcg_unidadeorganica"];
program = nprogram.Name;
if (entity.LogicalName != "fcg_concurs")

asp.net mvc 2 render view to string, instead of partial

I have this function:
public static string RenderViewToString(string controlName, object viewData) {
ViewDataDictionary vd = new ViewDataDictionary(viewData);
ViewPage vp = new ViewPage { ViewData = vd };
Control control = vp.LoadControl(controlName);
vp.Controls.Add(control);
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
using (HtmlTextWriter tw = new HtmlTextWriter(sw))
{
vp.RenderControl(tw);
}
}
return sb.ToString();
}
And I call it like this:
string body = StringHelpers.RenderViewToString("~/Areas/Public/Views/Shared/RegistrationEmail.ascx", new RegistrationEmailViewModel { User = user });
And it returns a html-table with the user-info.
But I was wondering if there is a way to edit this to I can can return a View as string? so I can add masterpage, so it'll be easier to design all potential mails going out?
Thanks in advance
/M
Check out MVCContrib's email template system for sending emails.
http://codevanced.net/post/Sending-HTML-emails-with-ASPNET-MVC2-and-MVCContrib.aspx
Update:
This question and/or this article might help if you don't want to include Mvccontrib. Although I use Mvccontrib every day, it's harmless.