I am using Drools 4 and when I am comparing two hashmap values with == it is not working. All other operators like >=,<=,<,>,!= are working fine. I am comparing as below. I am using map as . Is there any thing wrong with the statement. The map values will be updated in actions of the rules. I am able to see the updated values in map but comparison of the values is failing. I am using update(abc) to update the values.
eval((abc.getValue("123")).intValue() == (abc.getValue("456")).intValue())
Rule:
rule "008"
salience -18
agenda-group "CAP"
auto-focus true
when
testObj: TestObj(eval(fireNextPriority==true), categoryCount==18,
eval(!firedRules.contains(Integer.valueOf(23449)))
&& (date >= 1263925800000)
&& (date <= 4102338600000) && (date >= 1263925800000) && (date <= 4102338600000)
&& eval(1 == 1)
&& eval(testObj.getVariableValue("C1TC") == testObj.getVariableValue("Y1TC")))
then
System.out.println("Firing rule: CAP - 008");
testObj.setStatus(true);
testObj.setPriority(1);
testObj.addToFiredRules(23449);
update(testObj);
testObj.addVariableValue("C1PC", testObj.getVariableValue("C1PC")-
testObj.getVariableValue("C1OF"));
end
Object which we are using:
public class TestObj{
Long date;
Integer categoryCount;
boolean status = false;
boolean executeFinalRule = false;
boolean executeFinalRuleForCatg = true;
boolean fireNextPriority = true;
Set<Integer> firedRules = new HashSet<Integer>();
private int priority;
Map<String, Integer> variableValues = new HashMap<String, Integer>();
public Integer getCategoryCount() {
return categoryCount;
}
public void setCategoryCount(Integer categoryCount) {
this.categoryCount = categoryCount;
}
public void increaseCategoryCount(){
this.categoryCount++;
}
public void addVariableValue(String variableCode, Integer count){
if (count < 0) count = 0;
this.variableValues.put(variableCode, count);
}
public Integer getVariableValue(String variableCode){
Integer value = this.variableValues.get(variableCode);
return value == null? 0 : value;
}
public boolean isStatus() {
return status;
}
public Set<Integer> getFiredRules() {
return firedRules;
}
public void setFiredRules(Set<Integer> firedRules) {
this.firedRules = firedRules;
}
public void addToFiredRules(int l){
this.firedRules.add(l);
}
}
Thanks in advance.
I've never used Drools 4.x, so these are observations based of my (old) knowledge of 5.1.1 - they may not be accurate in your case.
eval(fireNextPriority==true)
It's remarkable that this works. eval does not maintain the context of the enclosing pattern (fact), so normally you'd have to write
eval(!firedRules.contains(Integer.valueOf(23449))
Same thing.
eval(testObj.getVariableValue("C1TC") == testObj.getVariableValue("Y1TC"))
This is as I'd write it from 5.1 onwards.
The strange thing is
testObj.addVariableValue("C1PC", testObj.getVariableValue("C1PC")
testObj.getVariableValue("C1OF"));
(DID I MESS THIS UP WHILE EDITING?) These changes are after the update call, which means that they won't be seen by the engine. Has the update of map entries "C1TC" and/or "Y1TC" been done likewise in another rule? Then they won't be equal to Drools, even if they are to Java...
Related
I've been going nuts over this. Nothing in my IF loop is firing through my test class and I cannot figure out why. I have done a lot of reading online and it appears that I am doing things correctly but it still hasn't solved my code coverage. This is the last line that runs:
If (isWithin == True){
after that I can't get anything to run within that IF loop, I have reversed the logic and it still doesn't run. I feel like I will kick myself when someone points it out but here is my code:
trigger caseCreatedDurringBusinessHours on Case (after insert) {
//Create list and map for cases
List<case> casesToUpdate = new List<case>();
Map<Id, case> caseMap = new Map<Id, case>();
// Get the default business hours
BusinessHours bh = [SELECT Id FROM BusinessHours WHERE IsDefault=true];
// Create Datetime on for now in the local timezone.
Datetime targetTime =System.now();
// Find whether the time now is within the default business hours
Boolean isWithin;
if ( Test.isRunningTest() ){
Boolean isWithin = True;
}
else{
Boolean isWithin = BusinessHours.isWithin(bh.id, targetTime);
}
// Update cases being inserted if during business hours
If (isWithin == True){
// Add cases to map if not null
For(case newcase : trigger.new) {
if(newcase.id != null){
caseMap.put(newcase.Id, newcase);
}
}
// Check that cases are in the map before SOQL query and update
If(caseMap.size() > 0){
// Query cases
casesToUpdate = [SELECT Id, Created_During_Business_Hours__c FROM case WHERE Id IN: caseMap.keySet()];
// Assign new value for checkbox field
for (case c: casesToUpdate){
c.Created_During_Business_Hours__c = TRUE;
}
// if the list of cases isnt empty, update them
if (casesToUpdate.size() > 0)
{
update casesToUpdate;
}
}
}
}
and here is my test class:
#isTest
private class BusinessHoursTest {
#isTest static void createCaseNotInBusinessHours() {
case c = new case();
c.subject = 'Test Subject';
insert c;
}
}
I think you can just copy the main logic to the apex class and just call the method of apex class from the apex trigger.
So it will make it more easy to write the test class.
Let me know if you need more help in this.
I'm sure you've figured this out by now but this block of code is re-defining the isWithin variable inside of the if/else blocks:
Boolean isWithin;
if (Test.isRunningTest()) {
Boolean isWithin = True;
} else {
Boolean isWithin = BusinessHours.isWithin(bh.id, targetTime);
}
That needs to be:
Boolean isWithin;
if (Test.isRunningTest()) {
isWithin = True;
} else {
isWithin = BusinessHours.isWithin(bh.id, targetTime);
}
Or rather a ternary operator for the cleanest code:
Boolean isWithin = !Test.isRunningTest() ? BusinessHours.isWithin(bh.id, targetTime) : true;
I have a custom item reader to return a list of records from table.My job is running in an infinite loop as the reader contract is not met.Any suggestions on this pls?
public class customReader implements ItemReader<List<T>>{
#Autowired
customDao customDao;
static List<T> CCTransDlyLg = null;
#Override
public List<T> read() throws Exception {
if(CCTransDlyLg==null || (CCTransDlyLg!=null && CCTransDlyLg.size()==0)){
CCTransDlyLg=customDao.getList();
}
log.info("CCTransDlyLg List:"+CCTransDlyLg.size());
return CCTransDlyLg.size()==0 ? null : CCTransDlyLg;
}
You're list never changes. Assuming you read a list that is size 5, your return statement will always return that same list. The logic of your ItemReader looks like you only want to return a single list (aka one call to the read() method).
As per Spring Batch Reader contract your method will be called again and again till it returns null.In your code if customDao succeeds your list will be always of Same Size it will never be zero. You need some condition to break out of that loop and return null .This is one possible solution by using a variable called index to break out of that loop.
On other note i see Mike answered your question i learned spring batch from his book and video itself :)
public class customReader implements ItemReader<List<T>> {
private static List<T> CCTransDlyLg = null;
#Autowired
customDao customDao;
private int index = 0;
#Override
public List<T> read() throws Exception {
if (CCTransDlyLg == null || (CCTransDlyLg != null && CCTransDlyLg.size() == 0)) {
CCTransDlyLg = customDao.getList();
index = CCTransDlyLg.size() + 1;
}
log.info("CCTransDlyLg List:" + CCTransDlyLg.size());
return index > CCTransDlyLg.size() ? null : CCTransDlyLg;
}
I have a table in my entity model called prices. It has several fields named value0, value1, value2, value3, value4... (these are their literal names, sigh..). I cannot rename them or in any way change them.
What I would like is to use an extended entity to create a new property called values. This would be a collection containing value1, value2 etc...
To get access to the values I would then simply need to write prices.values[1]
I need property changed notification for this.
So far I have tried this;
public partial class Prices
{
private ObservableCollection<double?> values = null;
public ObservableCollection<double?> Values
{
get
{
if (values != null)
values.CollectionChanged -= values_CollectionChanged;
else
values = new ObservableCollection<double?>(new double?[14]);
values[0] = value0;
values[1] = value1;
values[2] = value2;
values.CollectionChanged += values_CollectionChanged;
return values;
}
private set
{
value0 = value[0];
value1 = value[1];
value2 = value[2];
}
}
private void values_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Values = values;
}
}
The issue comes when trying to set values. if I try to set a value by writing
prices.values[0] = someValue;
The new value is not always reflected in the collection (i.e. when I have previously set value and then try to overwrite the value).
I am willing to try any approach that would achieve my goal, I am not precious about having my solution fixed (although if anyone can explain what I'm missing that would be great!)
You could implement an indexer on Prices class without using a collection.
You can use switch to select the property to write or you can use reflection.
In this case I use reflection.
public double? this[int index]
{
get
{
if (index < 0 || index > 13) throw new ArgumentOutOfRangeException("index");
string propertyName = "Value" + index;
return (double?)GetType().GetProperty(propertyName).GetValue(this);
}
set
{
if (index < 0 || index > 13) throw new ArgumentOutOfRangeException("index");
string propertyName = "Value" + index;
GetType().GetProperty(propertyName).SetValue(this, value);
// Raise your event here
}
}
I've a class defined as follows:
Public Class DeviceConfig
Private _maxNumCodesGlobal As Integer
Private _maxNumCodesDataMatrix As Integer
Private _maxNumCodesQR As Integer
Private _maxNumCodesBarcode As Integer
Private _partialResults As String
Private _allowIdenticalSymbols As String
Private _datamatrixValidation As Integer
Private _datamatrixValidationType
'AND MUCH MORE PROPERTIES
'GETTERS & SETTERS
End Class
as you can see it's a long list of properties in this class.
I need to compare the values of the properties from an instance with the values of the properties of another instance.
Is there a way to iterate through all of them, or even better, just comparing both classes and get true/false if they have the same properties values or not?
if instance1=instance2 then true
Thank you
I encountered the same problem and created this method. Hopefully it will help you.
It uses reflections to iterate through the public fields, ignoring those with the JsonIgnore annotation.
This method is not considering fields as List, Set, etc.
You can change it to work for properties instead of fields.
protected <T> boolean equals(T object1, T object2) {
Field[] fields = object1.getClass().getFields();
for (Field field : fields) {
if (field.getAnnotation(JsonIgnore.class)!= null) continue; //do not check the fields with JsonIgnore
Object value1;
Object value2;
try {
value1 = field.get(object1);
value2 = field.get(object2);
} catch (Exception e) {
logger.error("Error comparing objects. Exception: " + e.getMessage());
return false;
}
//comparing
if (value1 == null) {
if (value2 != null)
return false;
} else if (!value1.equals(value2))
return false;
}
return true;
}
I have a cell table with an async data provider. If I update the data via the data provider the table renders the new data correctly but the selection model still holds onto and returns old objects.
Any ideas how to refresh the selection model?
I think you should make your SelectionModel work with different instance of the same "logical" object using the appropriate ProvidesKey. For instance, you could use ProvidesKey that calls getId on the object, so that two objects with the same such ID would be considered equal; so even if the SelectionModel holds onto the old object, it can still answer "yes, it's selected" when you give it the new object.
FYI, this is exactly what the EntityProxyKeyProvider does (using the stableId of the proxy). And the SimpleKeyProvider, used by default when you don't specify one, uses the object itself as its key.
I came across the same issue. Currently I have this as single selection model.
SelectedRow = store it when you select it.
Then when data is reloaded you can clear it by
celltable.getSelectionModel().setSelected(SelectedRow, false);
I guess it is too late for you but hope it helps someone else.
Here is my manual method for refreshing the SelectionModel. This allows you to use the selectedSet() when needed and it will actually contain the current data, rather than the old data - including the removal of deleted rows and updated fields!
I have included bits & pieces of a class extending DataGrid. This should have all the logic at least to solve your problems.
When a row is selected, call saveSelectionKeys().
When the grid data is altered call refeshSelectedSet().
If you know the key type, you can replace the isSameKey() method with something easier to deal with. This class uses generics, so this method attempts to figure out the object conversion itself.
.
public abstract class AsyncDataGrid<T> extends DataGrid<T> {
...
private MultiSelectionModel<T> selectionModel_;
private ListDataProvider<T> dataProvider_;
private List<T> dataList_;
private Set<Object> priorSelectionKeySet_;
private boolean canCompareKeys_;
...
public AsyncDataGrid( final ProvidesKey<T> keyProvider ){
super( keyProvider );
...
dataProvider_ = new ListDataProvider<T>();
dataList_ = dataProvider_.getList();
canCompareKeys_ = true;
...
}
private void saveSelectionKeys(){
priorSelectionKeySet_ = new HashSet<Object>();
Set<T> selectedSet = selectionModel_.getSelectedSet();
for( Iterator<T> it = selectedSet.iterator(); it.hasNext(); ) {
priorSelectionKeySet_.add( super.getValueKey( it.next() ) );
}
}
private void refeshSelectedSet(){
selectionModel_.clear();
if( priorSelectionKeySet_ != null ){
if( !canCompareKeys_ ) return;
for( Iterator<Object> keyIt = priorSelectionKeySet_.iterator(); keyIt.hasNext(); ) {
Object priorKey = keyIt.next();
for( Iterator<T> it = dataList_.iterator(); it.hasNext(); ) {
T row = it.next();
Object rowKey = super.getValueKey( row );
if( isSameKey( rowKey, priorKey ) ) selectionModel_.setSelected( row, true );
}
}
}
}
private boolean isSameRowKey( final T row1, final T row2 ) {
if( (row1 == null) || (row2 == null) ) return false;
Object key1 = super.getValueKey( row1 );
Object key2 = super.getValueKey( row2 );
return isSameKey( key1, key2 );
}
private boolean isSameKey( final Object key1, final Object key2 ){
if( (key1 == null) || (key1 == null) ) return false;
if( key1 instanceof Integer ){
return ( ((Integer) key1) - ((Integer) key2) == 0 );
}
else if( key1 instanceof Long ){
return ( ((Long) key1) - ((Long) key2) == 0 );
}
else if( key1 instanceof String ){
return ( ((String) key1).equals( ((String) key2) ) );
}
canCompareKeys_ = false;
return false;
}
}
I fixed my particular issue by using the following code to return the visible selection. It uses the selection model to determine what is selected and combines this with what is visible. The objects themselves are returned from the CellTable data which is always upto date if the data has ever been changed via an async provider (the selection model data maybe stale but the keys will be correct)
public Set<T> getVisibleSelection() {
/*
* 1) the selection model contains selection that can span multiple pages -
* we want to return just the visible selection
* 2) return the object from the cellTable and NOT the selection - the
* selection may have old, stale, objects if the data has been updated
* since the selection was made
*/
Set<Object> selectedSet = getKeys(selectionModel.getSelectedSet());
List<T> visibleSet = cellTable.getVisibleItems();
Set<T> visibleSelectionSet = new HashSet<T>();
for (T visible : visibleSet) {
if (selectedSet.contains(KEY_PROVIDER.getKey(visible))) {
visibleSelectionSet.add(visible);
}
}
return visibleSelectionSet;
}
public static Set<Object> getKeys(Collection<T> objects) {
Set<Object> ids = new HashSet<Object>();
for (T object : objects) {
ids.add(KEY_PROVIDER.getKey(object));
}
return ids;
}