diff --git a/drools-compiler/src/test/java/org/drools/compiler/oopath/OOPathQueriesTest.java b/drools-compiler/src/test/java/org/drools/compiler/oopath/OOPathQueriesTest.java new file mode 100644 index 000000000000..75ae24ac8dc8 --- /dev/null +++ b/drools-compiler/src/test/java/org/drools/compiler/oopath/OOPathQueriesTest.java @@ -0,0 +1,290 @@ +/* + * Copyright 2017 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +package org.drools.compiler.oopath; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.drools.compiler.oopath.model.Group; +import org.drools.compiler.oopath.model.Man; +import org.drools.compiler.oopath.model.Person; +import org.drools.compiler.oopath.model.Room; +import org.drools.compiler.oopath.model.SensorEvent; +import org.drools.compiler.oopath.model.Thing; +import org.drools.compiler.oopath.model.Woman; +import org.junit.Test; +import org.kie.api.io.ResourceType; +import org.kie.api.runtime.KieSession; +import org.kie.api.runtime.rule.QueryResults; +import org.kie.api.runtime.rule.QueryResultsRow; +import org.kie.api.runtime.rule.Variable; +import org.kie.internal.utils.KieHelper; +import static org.assertj.core.api.Assertions.assertThat; + +public class OOPathQueriesTest { + + @Test + public void testQueryFromCode() { + final String drl = + "import org.drools.compiler.oopath.model.Thing;\n" + + "query isContainedIn( Thing $x, Thing $y )\n" + + " $y := /$x/children\n" + + "or\n" + + " ( $z := /$x/children and isContainedIn( $z, $y; ) )\n" + + "end\n"; + + final List itemList = Arrays.asList(new String[] { "display", "keyboard", "processor" }); + + final KieSession ksession = new KieHelper().addContent( drl, ResourceType.DRL ) + .build() + .newKieSession(); + + Thing smartphone = new Thing("smartphone"); + for ( String item : itemList ) { + Thing component = new Thing(item); + smartphone.addChild(component); + } + + ksession.insert(smartphone); + + QueryResults queryResults = ksession.getQueryResults("isContainedIn", new Object[] { smartphone, Variable.v }); + List resultList = new ArrayList<>(); + for(QueryResultsRow row : queryResults) { + Thing component = (Thing) row.get("$y"); + resultList.add(component.getName()); + } + + assertThat(resultList).as("Querry does not contain all items").containsAll(itemList); + + ksession.dispose(); + } + + @Test + public void testReactiveQuery() { + final String drl = + "import org.drools.compiler.oopath.model.Room;\n" + + "import org.drools.compiler.oopath.model.Sensor;\n" + + "import org.drools.compiler.oopath.model.SensorEvent;\n" + + "query temperature ( Room $r, double $t )\n" + + " $t := /$r/temperatureSensor/value\n" + + "end\n" + + "" + + "rule \"Change sensor value\" when\n" + + " $e : SensorEvent( $s : sensor, $v : value)\n" + + "then\n" + + " modify($s) { setValue($v) }\n" + + " retract($e)\n" + + "end\n" + + "" + + "rule \"Turn heating on\" when\n" + + " $r : Room()\n" + + " temperature( $r, $t; )\n" + + " eval( $t < 20 )" + + "then\n" + + " $r.getHeating().setOn(true);\n" + + "end\n" + + "rule \"Turn heating off\" when\n" + + " $r : Room()\n" + + " temperature( $r, $t; )\n" + + " eval( $t > 20 )" + + "then\n" + + " $r.getHeating().setOn(false);\n" + + "end\n"; + + Room room = new Room("Room"); + + final KieSession ksession = new KieHelper().addContent( drl, ResourceType.DRL ) + .build() + .newKieSession(); + + room.getTemperatureSensor().setValue(15); + room.getHeating().setOn(false); + ksession.insert(room); + ksession.insert(room.getTemperatureSensor()); + ksession.insert(room.getHeating()); + ksession.fireAllRules(); + assertThat(room.getHeating().isOn()).as("Temperature is bellow 20 degrees of Celsius. Heating should be turned on.").isTrue(); + + ksession.insert(new SensorEvent(room.getTemperatureSensor(), 25)); + ksession.fireAllRules(); + assertThat(room.getHeating().isOn()).as("Temperature is higher than 20 degrees of Celsius. Heating should be turned off.").isFalse(); + + ksession.dispose(); + } + + @Test + public void testNonReactiveOOPathInQuery() { + final String drl = + "import org.drools.compiler.oopath.model.Room;\n" + + "import org.drools.compiler.oopath.model.Sensor;\n" + + "import org.drools.compiler.oopath.model.SensorEvent;\n" + + "query temperature ( Room $r, double $t )\n" + + " $t := /$r?/temperatureSensor/value\n" + + "end\n" + + "" + + "rule \"Change sensor value\" when\n" + + " $e : SensorEvent( $s : sensor, $v : value)\n" + + "then\n" + + " modify($s) { setValue($v) }\n" + + " retract($e)\n" + + "end\n" + + "" + + "rule \"Turn heating on\" when\n" + + " $r : Room()\n" + + " temperature( $r, $t; )\n" + + " eval( $t < 20 )" + + "then\n" + + " $r.getHeating().setOn(true);\n" + + "end\n" + + "rule \"Turn heating off\" when\n" + + " $r : Room()\n" + + " temperature( $r, $t; )\n" + + " eval( $t > 20 )" + + "then\n" + + " $r.getHeating().setOn(false);\n" + + "end\n"; + + Room room = new Room("Room"); + + final KieSession ksession = new KieHelper().addContent( drl, ResourceType.DRL ) + .build() + .newKieSession(); + + room.getTemperatureSensor().setValue(15); + room.getHeating().setOn(false); + ksession.insert(room); + ksession.insert(room.getTemperatureSensor()); + ksession.insert(room.getHeating()); + ksession.fireAllRules(); + assertThat(room.getHeating().isOn()).as("Temperature is bellow 20 degrees of Celsius. Heating should be turned on.").isTrue(); + + ksession.insert(new SensorEvent(room.getTemperatureSensor(), 25)); + ksession.fireAllRules(); + assertThat(room.getHeating().isOn()).as("Query is not reactive. Heating should still be turned on.").isTrue(); + + ksession.dispose(); + } + + @Test + public void testPullOnlyQueryWithOOPath() { + final String drl = + "import org.drools.compiler.oopath.model.Room;\n" + + "import org.drools.compiler.oopath.model.Sensor;\n" + + "import org.drools.compiler.oopath.model.SensorEvent;\n" + + "query temperature ( Room $r, double $t )\n" + + " $t := /$r/temperatureSensor/value\n" + + "end\n" + + "" + + "rule \"Change sensor value\" when\n" + + " $e : SensorEvent( $s : sensor, $v : value)\n" + + "then\n" + + " modify($s) { setValue($v) }\n" + + " retract($e)\n" + + "end\n" + + "" + + "rule \"Turn heating on\" when\n" + + " $r : Room()\n" + + " ?temperature( $r, $t; )\n" + + " eval( $t < 20 )" + + "then\n" + + " $r.getHeating().setOn(true);\n" + + "end\n" + + "rule \"Turn heating off\" when\n" + + " $r : Room()\n" + + " ?temperature( $r, $t; )\n" + + " eval( $t > 20 )" + + "then\n" + + " $r.getHeating().setOn(false);\n" + + "end\n"; + + Room room = new Room("Room"); + + final KieSession ksession = new KieHelper().addContent( drl, ResourceType.DRL ) + .build() + .newKieSession(); + + room.getTemperatureSensor().setValue(15); + room.getHeating().setOn(false); + ksession.insert(room); + ksession.insert(room.getTemperatureSensor()); + ksession.insert(room.getHeating()); + ksession.fireAllRules(); + assertThat(room.getHeating().isOn()).as("Temperature is bellow 20 degrees of Celsius. Heating should be turned on.").isTrue(); + + ksession.insert(new SensorEvent(room.getTemperatureSensor(), 25)); + ksession.fireAllRules(); + assertThat(room.getHeating().isOn()).as("Query is not reactive. Heating should still be turned on.").isTrue(); + + ksession.dispose(); + } + + @Test + public void testPullOnlyQueryWithoutOOPath() { + final String drl = + "import org.drools.compiler.oopath.model.Room;\n" + + "import org.drools.compiler.oopath.model.Sensor;\n" + + "import org.drools.compiler.oopath.model.SensorEvent;\n" + + "query temperature ( Room $r, double $t )\n" + + " $r := Room()\n" + + " $s : Sensor() from $r.getTemperatureSensor()\n" + + " $t := Double() from $s.getValue()\n" + + "end\n" + + "" + + "rule \"Change sensor value\" when\n" + + " $e : SensorEvent( $s : sensor, $v : value)\n" + + "then\n" + + " modify($s) { setValue($v) }\n" + + " retract($e)\n" + + "end\n" + + "" + + "rule \"Turn heating on\" when\n" + + " $r : Room()\n" + + " ?temperature( $r, $t; )\n" + + " eval( $t < 20 )" + + "then\n" + + " $r.getHeating().setOn(true);\n" + + "end\n" + + "rule \"Turn heating off\" when\n" + + " $r : Room()\n" + + " ?temperature( $r, $t; )\n" + + " eval( $t > 20 )" + + "then\n" + + " $r.getHeating().setOn(false);\n" + + "end\n"; + + Room room = new Room("Room"); + + final KieSession ksession = new KieHelper().addContent( drl, ResourceType.DRL ) + .build() + .newKieSession(); + + room.getTemperatureSensor().setValue(15); + room.getHeating().setOn(false); + ksession.insert(room); + ksession.insert(room.getTemperatureSensor()); + ksession.insert(room.getHeating()); + ksession.fireAllRules(); + assertThat(room.getHeating().isOn()).as("Temperature is bellow 20 degrees of Celsius. Heating should be turned on.").isTrue(); + + ksession.insert(new SensorEvent(room.getTemperatureSensor(), 25)); + ksession.fireAllRules(); + assertThat(room.getHeating().isOn()).as("Query is not reactive. Heating should still be turned on.").isTrue(); + + ksession.dispose(); + } +} diff --git a/drools-compiler/src/test/java/org/drools/compiler/oopath/model/Appliance.java b/drools-compiler/src/test/java/org/drools/compiler/oopath/model/Appliance.java new file mode 100644 index 000000000000..66c5c208c543 --- /dev/null +++ b/drools-compiler/src/test/java/org/drools/compiler/oopath/model/Appliance.java @@ -0,0 +1,39 @@ +/* + * Copyright 2017 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +package org.drools.compiler.oopath.model; + +import org.drools.core.phreak.AbstractReactiveObject; + +public class Appliance extends AbstractReactiveObject { + private boolean on; + + public Appliance() { + on = false; + } + + public Appliance(boolean on) { + this.on = on; + notifyModification(); + } + + public boolean isOn() { + return on; + } + + public void setOn(boolean on) { + this.on = on; + } +} diff --git a/drools-compiler/src/test/java/org/drools/compiler/oopath/model/Room.java b/drools-compiler/src/test/java/org/drools/compiler/oopath/model/Room.java new file mode 100644 index 000000000000..d18d59a83656 --- /dev/null +++ b/drools-compiler/src/test/java/org/drools/compiler/oopath/model/Room.java @@ -0,0 +1,77 @@ +/* + * Copyright 2017 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +package org.drools.compiler.oopath.model; + +import org.drools.core.phreak.AbstractReactiveObject; + +public class Room extends AbstractReactiveObject { + private String name; + + private Sensor lightSensor = new Sensor(); + private Sensor temperatureSensor = new Sensor(); + + private Appliance light = new Appliance(); + private Appliance heating = new Appliance(); + + public Room(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + notifyModification(); + } + + public Sensor getLightSensor() { + return lightSensor; + } + + public void setLightSensor(Sensor lightSensor) { + this.lightSensor = lightSensor; + notifyModification(); + } + + public Sensor getTemperatureSensor() { + return temperatureSensor; + } + + public void setTemperatureSensor(Sensor temperatureSensor) { + this.temperatureSensor = temperatureSensor; + notifyModification(); + } + + public Appliance getLight() { + return light; + } + + public void setLight(Appliance light) { + this.light = light; + notifyModification(); + } + + public Appliance getHeating() { + return heating; + } + + public void setHeating(Appliance heating) { + this.heating = heating; + notifyModification(); + } +} diff --git a/drools-compiler/src/test/java/org/drools/compiler/oopath/model/Sensor.java b/drools-compiler/src/test/java/org/drools/compiler/oopath/model/Sensor.java new file mode 100644 index 000000000000..93e2f53d1669 --- /dev/null +++ b/drools-compiler/src/test/java/org/drools/compiler/oopath/model/Sensor.java @@ -0,0 +1,31 @@ +/* + * Copyright 2017 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +package org.drools.compiler.oopath.model; + +import org.drools.core.phreak.AbstractReactiveObject; + +public class Sensor extends AbstractReactiveObject { + private double value = 0; + + public double getValue() { + return value; + } + + public void setValue(double value) { + this.value = value; + notifyModification(); + } +} diff --git a/drools-compiler/src/test/java/org/drools/compiler/oopath/model/SensorEvent.java b/drools-compiler/src/test/java/org/drools/compiler/oopath/model/SensorEvent.java new file mode 100644 index 000000000000..4b84165ecb72 --- /dev/null +++ b/drools-compiler/src/test/java/org/drools/compiler/oopath/model/SensorEvent.java @@ -0,0 +1,42 @@ +/* + * Copyright 2017 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +package org.drools.compiler.oopath.model; + +public class SensorEvent { + private Sensor sensor; + private double value; + + public SensorEvent(Sensor sensor, double value) { + this.sensor = sensor; + this.value = value; + } + + public Sensor getSensor() { + return sensor; + } + + public void setSensor(Sensor sensor) { + this.sensor = sensor; + } + + public double getValue() { + return value; + } + + public void setValue(double value) { + this.value = value; + } +}