Drools 6.4.0 rule inheritance - multiple rules extends one parent - drools

I am trying to package multiple drl files each one has multiple rules extending same parent rule BaseRule.
Getting NullPointerException while calling
kbuilder.add(ResourceFactory.newFileResource(file), ResourceType.DRL);
Looks like the logic used below is not correct in KnowledgeBuilderImpl - sortRulesByDependency()
for (RuleDescr ruleDescr : packageDescr.getRules()) {
if (ruleDescr.isQuery()) {
queries.add(ruleDescr);
} else if (!ruleDescr.hasParent()) {
roots.add(ruleDescr);
} else {
if (pkg.getRule(ruleDescr.getParentName()) != null) {
// The parent of this rule has been already compiled
compiledRules.add(ruleDescr.getParentName());
}
List<RuleDescr> childz = children.get(ruleDescr.getParentName());
if (childz == null) {
childz = new ArrayList<RuleDescr>();
children.put(ruleDescr.getParentName(), childz);
}
childz.add(ruleDescr);
}
}
for (String compiledRule : compiledRules) {
List<RuleDescr> childz = children.remove( compiledRule );
roots.addAll( childz );
}
compiledRules list contains BaseRule name multiple times because more than one rule extending BaseRule.
After first time remove, next time it is going to return NULL and that will cause NullPointerException in roots.addAll
Any idea why there is no check to avoid this case?

Related

From RxJava2, How can I compare and filter two observables if the values are equal?

I am new to RxJava2.
I am trying to get a list of Transaction object both from cache and from server.
I want to compare the server value to cache value and if the server value is the same, then ignore it.
I was able to do it easily using .scan() because we can return null and when null is returned from the .scan() the value got ignored(filtered).
RxJava 1
private Observable<List<Transaction>> getTransactionsFromCacheAndServer() {
return Observable.concat(
getTransactionsFromCache(),
getTransactionsFromServer()
)
.scan((p1, p2) -> {
if (p1 == null && p2 != null) {
return p2;
} else if (p1 != null && !isListSame(p1, p2)) {
return p2;
} else {
return null;
}
});
}
With RxJava 2, since I cannot return null anymore, things are not easy.
RxJava 2
private Observable<List<Transaction>> getTransactionsFromCacheAndServer() {
return Observable.concat(
getTransactionsFromCache(),
getTransactionsFromServer()
)
.map(FilterObject::new)
.scan((filterObject1, filterObject2) -> {
List<Transaction> p1 = (List<Transaction>)filterObject1.value;
List<Transaction> p2 = (List<Transaction>)filterObject2.value;
if (p1.size() == 0 && p2.size() > 0) {
return filterObject2;
} else if (!isListSame(p1, p2)) {
return filterObject2;
} else {
filterObject2.filter = true;
return filterObject2;
}
})
.filter(filterObject -> !filterObject.filter)
.map(filterObject -> (List<Transaction>)filterObject.value);
}
Where FilterObject is:
public class FilterObject {
public Object value;
public boolean filter;
public FilterObject(Object value) {
this.value = value;
}
}
Even though I can achieve the same thing using above method, it seems very ugly. Also I had to include two maps which might not be so performance friendly.
Is there a simple/clean way to achieve what I want?
I don't think there is a generic solution to this problem, since an empty list and a list that needs to be filtered (which happens to be empty in all cases) are two different things (the output of the scan) and needs to be handled differently.
However, in your particular case you never emit an empty list, except maybe for the first output.
(I am using String instead Transaction, shouldn't matter)
private Observable<List<String>> getTransactionsFromCacheAndServer() {
return Observable.concat(
getTransactionsFromCache(),
getTransactionsFromServer()
)
.filter(list -> !list.isEmpty())
// If you prefer a consistent empty list over the first
// empty list emission getting filtered
.startWith((List<String>) Collections.EMPTY_LIST)
// Newly emitted value cannot be empty, it only depends only on the comparison
.distinctUntilChanged(this::isListSame);
}
That's the closest I could get with as few operators as possible. Hope it solves your problem.
Based on andras' answer, I modified little bit to achieve what I want.
private Observable<List<String>> getTransactionsFromCacheAndServer() {
return Observable.concat(
getTransactionsFromCache(),
getTransactionsFromServer()
)
.filter(list -> !list.isEmpty())
.distinctUntilChanged(this::isListSame)
.switchIfEmpty(Observable.just(new ArrayList<>()));
}
Andreas' answer will always receive an empty list and then a real data.
My solution above will receive:
1. Data from cache (and then data from server if different)
2. Empty list if both cache and server returns Empty list.

CRM 2011 : Plugin to create duplicate records

i created a simple plugin to create a duplicate record that refers to the parent record.
Here is my code
var pluginExecutionContext = localContext.PluginExecutionContext;
IOrganizationService service = localContext.OrganizationService;
abc= pluginExecutionContext.InputParameters["Target"] as Entity;
if (pluginExecutionContext.Depth == 1)
{
Guid abcId = abc.Id;
Entity abcCopy = new Entity("mcg_abc");
if (abc.Attributes.Contains("mcg_abccategoryoptioncode"))
{
abcCopy.Attributes["mcg_abccategoryoptioncode"] = abc.GetAttributeValue<OptionSetValue>("mcg_abccategoryoptioncode");
}
if (abc.Attributes.Contains("mcg_effectivedate"))
{
abcCopy.Attributes["mcg_effectivedate"] = isp.GetAttributeValue<DateTime>("mcg_effectivedate");
}
if (abc.Attributes.Contains("mcg_startdate"))
{
abcCopy.Attributes["mcg_startdate"] = isp.GetAttributeValue<DateTime>("mcg_startdate");
}
if (abc.Attributes.Contains("mcg_enddate"))
{
abcCopy.Attributes["mcg_enddate"] = isp.GetAttributeValue<DateTime>("mcg_enddate");
}
if (abc.Attributes.Contains("mcg_amendeddate"))
{
abcCopy.Attributes["mcg_amendeddate"] = isp.GetAttributeValue<DateTime>("mcg_amendeddate");
}
if ((abc.GetAttributeValue<OptionSetValue>("mcg_abccategoryoptioncode").Value) == 803870001)
{
//Some more fields;
}
else
{
//Some more fields;
}
// SOme more fields;
abcCopy.Attributes["mcg_parentabc"] = new EntityReference("mcg_abc", abc.Id);
service.Create(abcCopy);
}
Now the problem is all the fields before the below check are getting copied
if ((abc.GetAttributeValue<OptionSetValue>("mcg_abccategoryoptioncode").Value) == 803870001)
However fields after this check are not getting copied.
Please if anybody could suggest what mistake i have made.
In case you take field from Target - this field was updated on a client side. In case field was not updated - it would not be in Target. You should use Images to get values of unchanged fields.
The field must be empty so a exception may arise. Try to use the plugin image or change your code to this way:
if (abc.Attributes.Contains("mcg_abccategoryoptioncode")){
if ((abc.GetAttributeValue<OptionSetValue>("mcg_abccategoryoptioncode").Value) == 803870001)
....

MongoDB 'upsert' from Grails

I'm trying to implement a simple "insert or update" (so-called 'upsert') method in Grails / GORM / mongodb plug-in / MongoDB.
The approach I used with Hibernate (using merge) fails with a duplicate key error. I presume perhaps merge() isn't a supported operation in mongodb GORM, and tried to get to the native upsert method through GMongo.
I finally have a version that works (as posted below), but it is probably not the best way, as adding any fields to the object being saved will break the code silently.
public void upsertPrefix(p) {
def o = new BasicDBObject()
o.put("_id", p.id)
o.put("someValue", p.someValue)
o.put("otherValue", p.otherValue)
// DBObject o = p as DBObject // No signature of method: mypackage.Prefix.keySet() is applicable for argument types: () values: []
db.prefix.update([_id : p.id], o, true, false)
// I actually would want to pass p instead of o here, but that fails with:
// No signature of method: com.gmongo.internal.DBCollectionPatcher$__clinit__closure2.doCall() is applicable for argument types: (java.util.ArrayList) values: [[[_id:keyvalue], mypackage.Prefix : keyvalue, ...]]
/* All of these other more "Hibernatesque" approaches fail:
def existing = Prefix.get(p.id)
if (existing != null) {
p.merge(flush:true) // E11000 duplicate key error
// existing.merge(p) // Invocation failed: Message: null
// Prefix.merge(p) // Invocation failed: Message: null
} else {
p.save(flush:true)
}
*/
}
I guess I could introduce another POJO-DbObject mapping framework to the mix, but that would complicate things even more, duplicate what GORM is already doing and may introduce additional meta-data.
Any ideas how to solve this in the simplest fashion?
Edit #1: I now tried something else:
def existing = Prefix.get(p.id)
if (existing != null) {
// existing.properties = p.properties // E11000 duplicate key error...
existing.someValue = p.someValue
existing.otherValue = p.otherValue
existing.save(flush:true)
} else {
p.save(flush:true)
}
Once again the non-commented version works, but is not well maintainable. The commented version which I'd like to make work fails.
Edit #2:
Version which works:
public void upsertPrefix(p) {
def o = new BasicDBObject()
p.properties.each {
if (! (it.key in ['dbo'])) {
o[it.key] = p.properties[it.key]
}
}
o['_id'] = p.id
db.prefix.update([_id : p.id], o, true, false)
}
Version which never seems to insert anything:
def upsertPrefix(Prefix updatedPrefix) {
Prefix existingPrefix = Prefix.findOrCreateById(updatedPrefix.id)
updatedPrefix.properties.each { prop ->
if (! prop.key in ['dbo', 'id']) { // You don't want to re-set the id, and dbo is r/o
existingPrefix.properties[prop.key] = prop.value
}
}
existingPrefix.save() // Never seems to insert anything
}
Version which still fails with duplicate key error:
def upsertPrefix(p) {
def existing = Prefix.get(p.id)
if (existing != null) {
p.properties.each { prop ->
print prop.key
if (! prop.key in ['dbo', 'id']) {
existingPrefix.properties[prop.key] = prop.value
}
}
existing.save(flush:true) // Still fails with duplicate key error
} else {
p.save(flush:true)
}
}
Assuming you have either an updated version of the object, or a map of the properties you need to update with their new values, you could loop over those and apply the updates for each property.
Something like this:
def upsert(Prefix updatedPrefix) {
Prefix existingPrefix = Prefix .findOrCreateById(updatedPrefix.id)
updatedPrefix.properties.each { prop ->
if (prop.key != 'id') { // You don't want to re-set the id
existingPrefix.properties[prop.key] = prop.value
}
}
existingPrefix.save()
}
How to exclude updating the ID may not be quite correct, so you might have to play with it a bit. You also might consider only updating a property if it's corresponding new value is different from the existing one, but that's essentially just an optimization.
If you have a map, you might also consider doing the update the way the default controller scaffolding does:
prefixInstance.properties = params
MongoDB has native support for upsert. See the findAndModify Command with upsert parameter true.

Symfony: exclude empty values from form save

I have a many to many relation between Product and Properties. I'm using embedRelation() in my Product form to edit a Product and it's Properties. Properties includes images which causes my issue. Every time I save the form the updated_at column is updated for file properties even when no file is uploaded.
Therefore, I want to exclude empty properties when saving my form.
I'm using Symfony 1.4 and Doctrine 1.2.
I'm thinking something like this in my ProductForm.class.php, but I need some input on how to make this work.
Thanks
class ProductForm extends BaseProductForm
{
public function configure()
{
unset($this['created_at'], $this['updated_at'], $this['id'], $this['slug']);
$this->embedRelation('ProductProperties');
}
public function saveEmbeddedForms($con = null, $forms = null)
{
if (null === $forms)
{
$properties = $this->getValue('ProductProperties');
$forms = $this->embeddedForms;
foreach($properties as $p)
{
// If property value is empty, unset from $forms['ProductProperties']
}
}
}
}
I ended up avoiding Symfony's forms and saving models instead of saving forms. It can be easier when playing with embedded forms. http://arialdomartini.wordpress.com/2011/04/01/how-to-kill-symfony%E2%80%99s-forms-and-live-well/
Solved it by checking if posted value is a file, and if both filename and value_delete is null I unset from the array. It might not be best practice, but it works for now.
Solution based on http://www.symfony-project.org/more-with-symfony/1_4/en/06-Advanced-Forms
class ProductPropertyValidatorSchema extends sfValidatorSchema
{
protected function configure($options = array(), $messages = array())
{
// N0thing to configure
}
protected function doClean($values)
{
$errorSchema = new sfValidatorErrorSchema($this);
foreach($values as $key => $value)
{
$errorSchemaLocal = new sfValidatorErrorSchema($this);
if(array_key_exists('value_delete', $values))
{
if(!$value && !$values['value_delete'])
{
unset($values[$key]);
}
}
// Some error for this embedded-form
if (count($errorSchemaLocal))
{
$errorSchema->addError($errorSchemaLocal, (string) $key);
}
}
// Throws the error for the main form
if (count($errorSchema))
{
throw new sfValidatorErrorSchema($this, $errorSchema);
}
return $values;
}
}

tinymce.dom.replace throws an exception concerning parentNode

I'm writing a tinyMce plugin which contains a section of code, replacing one element for another. I'm using the editor's dom instance to create the node I want to insert, and I'm using the same instance to do the replacement.
My code is as follows:
var nodeData =
{
"data-widgetId": data.widget.widgetKey(),
"data-instanceKey": "instance1",
src: "/content/images/icon48/cog.png",
class: "widgetPlaceholder",
title: data.widget.getInfo().name
};
var nodeToInsert = ed.dom.create("img", nodeData);
// Insert this content into the editor window
if (data.mode == 'add') {
tinymce.DOM.add(ed.getBody(), nodeToInsert);
}
else if (data.mode == 'edit' && data.selected != null) {
var instanceKey = $(data.selected).attr("data-instancekey");
var elementToReplace = tinymce.DOM.select("[data-instancekey=" + instanceKey + "]");
if (elementToReplace.length === 1) {
ed.dom.replace(elementToReplace[0], nodeToInsert);
}
else {
throw new "No element to replace with that instance key";
}
}
TinyMCE breaks during the replace, here:
replace : function(n, o, k) {
var t = this;
if (is(o, 'array'))
n = n.cloneNode(true);
return t.run(o, function(o) {
if (k) {
each(tinymce.grep(o.childNodes), function(c) {
n.appendChild(c);
});
}
return o.parentNode.replaceChild(n, o);
});
},
..with the error Cannot call method 'replaceChild' of null.
I've verified that the two argument's being passed into replace() are not null and that their parentNode fields are instantiated. I've also taken care to make sure that the elements are being created and replace using the same document instance (I understand I.E has an issue with this).
I've done all this development in Google Chrome, but I receive the same errors in Firefox 4 and IE8 also. Has anyone else come across this?
Thanks in advance
As it turns out, I was simply passing in the arguments in the wrong order. I should have been passing the node I wanted to insert first, and the node I wanted to replace second.