/*
* Copyright 2015 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.integrationtests;
import org.drools.compiler.Address;
import org.drools.compiler.Cheese;
import org.drools.compiler.CommonTestMethodBase;
import org.drools.compiler.DomainObject;
import org.drools.compiler.InsertedObject;
import org.drools.compiler.Interval;
import org.drools.compiler.Person;
import org.drools.compiler.Worker;
import org.drools.core.QueryResultsImpl;
import org.drools.core.QueryResultsRowImpl;
import org.drools.core.base.ClassObjectType;
import org.drools.core.base.DroolsQuery;
import org.drools.core.common.InternalFactHandle;
import org.drools.core.impl.StatefulKnowledgeSessionImpl;
import org.drools.core.reteoo.EntryPointNode;
import org.drools.core.reteoo.ObjectTypeNode;
import org.drools.core.reteoo.ObjectTypeNode.ObjectTypeNodeMemory;
import org.drools.core.runtime.rule.impl.FlatQueryResultRow;
import org.drools.core.runtime.rule.impl.FlatQueryResults;
import org.drools.core.spi.ObjectType;
import org.junit.Before;
import org.junit.Test;
import org.junit.rules.TestName;
import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.Message;
import org.kie.api.builder.Results;
import org.kie.api.definition.rule.Rule;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.conf.QueryListenerOption;
import org.kie.api.runtime.rule.FactHandle;
import org.kie.api.runtime.rule.LiveQuery;
import org.kie.api.runtime.rule.QueryResults;
import org.kie.api.runtime.rule.QueryResultsRow;
import org.kie.api.runtime.rule.Row;
import org.kie.api.runtime.rule.Variable;
import org.kie.api.runtime.rule.ViewChangedEventListener;
import org.kie.internal.utils.KieHelper;
import javax.xml.bind.JAXBContext;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
public class QueryTest extends CommonTestMethodBase {
@org.junit.Rule
public TestName testName = new TestName();
@Before
public void before() {
System.out.println( "] " + testName.getMethodName());
}
private static QueryResults getQueryResults(KieSession session, String queryName, Object... arguments ) throws Exception {
QueryResultsImpl results = (QueryResultsImpl) session.getQueryResults( queryName, arguments );
FlatQueryResults flatResults = new FlatQueryResults(results);
assertEquals( "Query results size", results.size(), flatResults.size() );
assertEquals( "Query results identifiers", results.getIdentifiers().length, flatResults.getIdentifiers().length );
Set<String> resultIds = new TreeSet<String>(Arrays.asList(results.getIdentifiers()));
Set<String> flatIds = new TreeSet<String>(Arrays.asList(flatResults.getIdentifiers()));
assertArrayEquals("Flat query results identifiers", resultIds.toArray(), flatIds.toArray() );
FlatQueryResults copyFlatResults = roundTrip(flatResults);
String [] identifiers = results.getIdentifiers();
Iterator<QueryResultsRow> copyFlatIter = copyFlatResults.iterator();
for( int i = 0; i < results.size(); ++i ) {
QueryResultsRow row = results.get(i);
assertTrue( "Round-tripped flat query results contain less rows than original query results", copyFlatIter.hasNext());
QueryResultsRow copyRow = copyFlatIter.next();
for( String id : identifiers ) {
Object obj = row.get(id);
if( obj != null ) {
Object copyObj = copyRow.get(id);
assertTrue( "Flat query result [" + i + "] does not contain result: '" + id + "': " + obj + "/" + copyObj, obj != null && obj.equals(copyObj));
}
FactHandle fh = row.getFactHandle(id);
FactHandle copyFh = copyRow.getFactHandle(id);
if( fh != null ) {
assertNotNull( "Flat query result [" + i + "] does not contain facthandle: '" + ((InternalFactHandle) fh).getId() + "'", copyFh);
String fhStr = fh.toExternalForm();
fhStr = fhStr.substring(0, fhStr.lastIndexOf(":"));
String copyFhStr = copyFh.toExternalForm();
copyFhStr = copyFhStr.substring(0, copyFhStr.lastIndexOf(":"));
assertEquals( "Unequal fact handles for fact handle '" + ((InternalFactHandle) fh).getId() + "':",
fhStr, copyFhStr );
}
}
}
// check identifiers
Set<String> copyFlatIds = new TreeSet<String>(Arrays.asList(copyFlatResults.getIdentifiers()));
assertArrayEquals("Flat query results identifiers", flatIds.toArray(), copyFlatIds.toArray() );
return copyFlatResults;
}
private static <T> T roundTrip( Object obj ) throws Exception {
Class[] classes = { obj.getClass() };
JAXBContext ctx = getJaxbContext(classes);
String xmlOut = marshall(ctx, obj);
return unmarshall(ctx, xmlOut);
}
private static <T> T unmarshall( JAXBContext ctx, String xmlIn ) throws Exception {
ByteArrayInputStream xmlStrInputStream = new ByteArrayInputStream(xmlIn.getBytes(Charset.forName("UTF-8")));
Object out = ctx.createUnmarshaller().unmarshal(xmlStrInputStream);
return (T) out;
}
private static String marshall( JAXBContext ctx, Object obj ) throws Exception {
StringWriter writer = new StringWriter();
ctx.createMarshaller().marshal(obj, writer);
return writer.getBuffer().toString();
}
private static JAXBContext getJaxbContext( Class<?>... classes ) throws Exception {
List<Class<?>> jaxbClassList = new ArrayList<Class<?>>();
jaxbClassList.addAll(Arrays.asList(classes));
jaxbClassList.add(Cheese.class);
jaxbClassList.add(InsertedObject.class);
jaxbClassList.add(Person.class);
Class<?>[] jaxbClasses = jaxbClassList.toArray(new Class[jaxbClassList.size()]);
return JAXBContext.newInstance(jaxbClasses);
}
@Test
public void testQuery() throws Exception {
KieBase kbase = SerializationHelper.serializeObject(loadKnowledgeBase("simple_query_test.drl"));
KieSession session = createKieSession( kbase );
final Cheese stilton = new Cheese( "stinky",
5 );
FactHandle factHandle = session.insert( stilton );
session = SerializationHelper.getSerialisedStatefulKnowledgeSession(session, true);
String queryName = "simple query";
org.kie.api.runtime.rule.QueryResults results = getQueryResults(session, queryName);
assertEquals( 1,
results.size() );
QueryResultsRow row = results.iterator().next();
if( row instanceof FlatQueryResultRow ) {
FlatQueryResultRow flatRow = (FlatQueryResultRow) row;
assertEquals( 0, flatRow.getIdentifiers().size() );
} else if( row instanceof QueryResultsRowImpl ) {
QueryResultsRowImpl rowImpl = (QueryResultsRowImpl) row;
assertEquals( 0, rowImpl.getDeclarations().size() );
}
}
@Test
public void testQueryRemoval() throws Exception {
KieBase kbase = SerializationHelper.serializeObject(loadKnowledgeBase("simple_query_test.drl"));
KieSession session = createKieSession( kbase );
final Cheese stilton = new Cheese( "stinky",
5 );
session.insert( stilton );
session = SerializationHelper.getSerialisedStatefulKnowledgeSession(session, true);
org.kie.api.runtime.rule.QueryResults results = session.getQueryResults( "simple query" );
assertEquals( 1,
results.size() );
Rule rule = kbase.getKiePackage( "org.drools.compiler.test" ).getRules().iterator().next();
assertEquals( "simple query",
rule.getName());
kbase.removeQuery( "org.drools.compiler.test",
"simple query" );
assertTrue( kbase.getKiePackage( "org.drools.compiler.test" ).getRules().isEmpty() );
try {
results = session.getQueryResults( "simple query" );
} catch ( Exception e ) {
assertTrue( e.getMessage().endsWith( "does not exist") );
}
}
@Test
public void testQuery2() throws Exception {
KieBase kbase = SerializationHelper.serializeObject(loadKnowledgeBase("test_Query.drl"));
KieSession session = createKieSession( kbase );
session.fireAllRules();
QueryResults results = getQueryResults(session, "assertedobjquery" );
assertEquals( 1,
results.size() );
assertEquals( new InsertedObject( "value1" ),
((InternalFactHandle) results.iterator().next().getFactHandle( "assertedobj" )).getObject() );
}
@Test
public void testQueryWithParams() throws Exception {
KieBase kbase = SerializationHelper.serializeObject(loadKnowledgeBase("test_QueryWithParams.drl"));
KieSession session = createKieSession( kbase );
session.fireAllRules();
String queryName = "assertedobjquery";
String [] arguments = new String[]{"value1"};
QueryResultsImpl resultsImpl = (QueryResultsImpl) session.getQueryResults( queryName, arguments );
QueryResults results = getQueryResults( session, queryName, arguments );
assertEquals( 1,
results.size() );
InsertedObject value = new InsertedObject( "value1" );
assertEquals( value,
((InternalFactHandle) results.iterator().next().getFactHandle( "assertedobj" )).getObject() );
assertEquals( value,
results.iterator().next().get("assertedobj") );
results = getQueryResults( session, "assertedobjquery", new String[]{"value3"} );
assertEquals( 0,
results.size() );
results = getQueryResults( session, "assertedobjquery2", new String[]{null, "value2"} );
assertEquals( 1,
results.size() );
assertEquals( new InsertedObject( "value2" ),
((InternalFactHandle) results.iterator().next().getFactHandle( "assertedobj" )).getObject() );
results = getQueryResults(session, "assertedobjquery2", new String[]{"value3", "value2"} );
assertEquals( 1,
results.size() );
assertEquals( new InsertedObject( "value2" ),
((InternalFactHandle) results.iterator().next().getFactHandle( "assertedobj" )).getObject() );
}
@Test
public void testQueryWithMultipleResultsOnKnowledgeApi() throws Exception {
String str = "";
str += "package org.drools.compiler.test \n";
str += "import org.drools.compiler.Cheese \n";
str += "query cheeses \n";
str += " stilton : Cheese(type == 'stilton') \n";
str += " cheddar : Cheese(type == 'cheddar', price == stilton.price) \n";
str += "end\n";
KieBase kbase = SerializationHelper.serializeObject(loadKnowledgeBaseFromString(str));
KieSession session = createKieSession( kbase );
Cheese stilton1 = new Cheese( "stilton", 1 );
Cheese cheddar1 = new Cheese( "cheddar", 1 );
Cheese stilton2 = new Cheese( "stilton", 2 );
Cheese cheddar2 = new Cheese( "cheddar", 2 );
Cheese stilton3 = new Cheese( "stilton", 3 );
Cheese cheddar3 = new Cheese( "cheddar", 3 );
Set set = new HashSet();
List list = new ArrayList();
list.add( stilton1 );
list.add( cheddar1 );
set.add( list );
list = new ArrayList();
list.add( stilton2 );
list.add( cheddar2 );
set.add( list );
list = new ArrayList();
list.add( stilton3 );
list.add( cheddar3 );
set.add( list );
session.insert( stilton1 );
session.insert( stilton2 );
session.insert( stilton3 );
session.insert( cheddar1 );
session.insert( cheddar2 );
session.insert( cheddar3 );
org.kie.api.runtime.rule.QueryResults results = getQueryResults(session, "cheeses" );
assertEquals( 3, results.size() );
assertEquals( 2, results.getIdentifiers().length );
Set newSet = new HashSet();
for ( org.kie.api.runtime.rule.QueryResultsRow result : results ) {
list = new ArrayList();
list.add( result.get( "stilton" ) );
list.add( result.get( "cheddar" ) );
newSet.add( list );
}
assertEquals( set,
newSet );
FlatQueryResults flatResults = new FlatQueryResults( ((StatefulKnowledgeSessionImpl) session).getQueryResults( "cheeses" ) );
newSet = new HashSet();
for ( org.kie.api.runtime.rule.QueryResultsRow result : flatResults ) {
list = new ArrayList();
list.add( result.get( "stilton" ) );
list.add( result.get( "cheddar" ) );
newSet.add( list );
}
assertEquals( set,
newSet );
}
@Test
public void testTwoQuerries() throws Exception {
// @see JBRULES-410 More than one Query definition causes an incorrect
// Rete network to be built.
KieBase kbase = SerializationHelper.serializeObject(loadKnowledgeBase("test_TwoQuerries.drl"));
KieSession session = createKieSession( kbase );
final Cheese stilton = new Cheese( "stinky",
5 );
session.insert( stilton );
final Person per1 = new Person( "stinker",
"smelly feet",
70 );
final Person per2 = new Person( "skunky",
"smelly armpits",
40 );
session.insert( per1 );
session.insert( per2 );
QueryResults results = getQueryResults( session, "find stinky cheeses" );
assertEquals( 1,
results.size() );
results = getQueryResults( session, "find pensioners" );
assertEquals( 1,
results.size() );
}
@Test
public void testDoubleQueryWithExists() throws Exception {
KieBase kbase = SerializationHelper.serializeObject(loadKnowledgeBase("test_DoubleQueryWithExists.drl"));
KieSession session = createKieSession( kbase );
final Person p1 = new Person( "p1",
"stilton",
20 );
p1.setStatus( "europe" );
final FactHandle c1FactHandle = session.insert( p1 );
final Person p2 = new Person( "p2",
"stilton",
30 );
p2.setStatus( "europe" );
final FactHandle c2FactHandle = session.insert( p2 );
final Person p3 = new Person( "p3",
"stilton",
40 );
p3.setStatus( "europe" );
final FactHandle c3FactHandle = session.insert( p3 );
session.fireAllRules();
QueryResults results = session.getQueryResults( "2 persons with the same status" );
assertEquals( 2,
results.size() );
// europe=[ 1, 2 ], america=[ 3 ]
p3.setStatus( "america" );
session.update( c3FactHandle,
p3 );
session.fireAllRules();
results = session.getQueryResults( "2 persons with the same status" );
assertEquals( 1,
results.size() );
// europe=[ 1 ], america=[ 2, 3 ]
p2.setStatus( "america" );
session.update( c2FactHandle,
p2 );
session.fireAllRules();
results = session.getQueryResults( "2 persons with the same status" );
assertEquals( 1,
results.size() );
// europe=[ ], america=[ 1, 2, 3 ]
p1.setStatus( "america" );
session.update( c1FactHandle,
p1 );
session.fireAllRules();
results = getQueryResults( session, "2 persons with the same status" );
assertEquals( 2,
results.size() );
// europe=[ 2 ], america=[ 1, 3 ]
p2.setStatus( "europe" );
session.update( c2FactHandle,
p2 );
session.fireAllRules();
results = getQueryResults( session, "2 persons with the same status" );
assertEquals( 1,
results.size() );
// europe=[ 1, 2 ], america=[ 3 ]
p1.setStatus( "europe" );
session.update( c1FactHandle,
p1 );
session.fireAllRules();
results = session.getQueryResults( "2 persons with the same status" );
assertEquals( 1,
results.size() );
// europe=[ 1, 2, 3 ], america=[ ]
p3.setStatus( "europe" );
session.update( c3FactHandle,
p3 );
session.fireAllRules();
results = session.getQueryResults( "2 persons with the same status" );
assertEquals( 2,
results.size() );
}
@Test
public void testQueryWithCollect() throws Exception {
KieBase kbase = SerializationHelper.serializeObject(loadKnowledgeBase("test_Query.drl"));
KieSession session = createKieSession( kbase );
session.fireAllRules();
QueryResults results = getQueryResults( session, "collect objects" );
assertEquals( 1,
results.size() );
final QueryResultsRow row = results.iterator().next();
final List list = (List) row.get( "$list" );
assertEquals( 2,
list.size() );
}
@Test
public void testDroolsQueryCleanup() throws Exception {
KieBase kbase = SerializationHelper.serializeObject(loadKnowledgeBase("test_QueryMemoryLeak.drl"));
KieSession session = createKieSession( kbase );
KieSession ksession = kbase.newKieSession();
String workerId = "B1234";
Worker worker = new Worker();
worker.setId( workerId );
FactHandle handle = ksession.insert( worker );
ksession.fireAllRules();
assertNotNull( handle );
Object retractedWorker = null;
for ( int i = 0; i < 100; i++ ) {
retractedWorker = (Object) ksession.getQueryResults( "getWorker",
new Object[]{workerId} );
}
assertNotNull( retractedWorker );
StatefulKnowledgeSessionImpl sessionImpl = (StatefulKnowledgeSessionImpl) ksession;
Collection<EntryPointNode> entryPointNodes = sessionImpl.getKnowledgeBase().getRete().getEntryPointNodes().values();
EntryPointNode defaultEntryPointNode = null;
for ( EntryPointNode epNode : entryPointNodes ) {
if ( epNode.getEntryPoint().getEntryPointId().equals( "DEFAULT" ) ) {
defaultEntryPointNode = epNode;
break;
}
}
assertNotNull( defaultEntryPointNode );
Map<ObjectType, ObjectTypeNode> obnodes = defaultEntryPointNode.getObjectTypeNodes();
ObjectType key = new ClassObjectType( DroolsQuery.class );
ObjectTypeNode droolsQueryNode = obnodes.get( key );
Iterator<InternalFactHandle> it = ((ObjectTypeNodeMemory) sessionImpl.getNodeMemory( droolsQueryNode )).iterator();
assertFalse( it.hasNext() );
}
@Test
public void testQueriesWithVariableUnification() throws Exception {
String str = "";
str += "package org.drools.compiler.test \n";
str += "import org.drools.compiler.Person \n";
str += "query peeps( String $name, String $likes, int $age ) \n";
str += " $p : Person( $name := name, $likes := likes, $age := age ) \n";
str += "end\n";
KieBase kbase = SerializationHelper.serializeObject(loadKnowledgeBaseFromString(str));
KieSession ksession = createKieSession( kbase );
Person p1 = new Person( "darth",
"stilton",
100 );
Person p2 = new Person( "yoda",
"stilton",
300 );
Person p3 = new Person( "luke",
"brie",
300 );
Person p4 = new Person( "bobba",
"cheddar",
300 );
ksession.insert( p1 );
ksession.insert( p2 );
ksession.insert( p3 );
ksession.insert( p4 );
QueryResults results = getQueryResults(ksession, "peeps", new Object[]{Variable.v, Variable.v, Variable.v} );
assertEquals( 4, results.size() );
List names = new ArrayList();
for ( org.kie.api.runtime.rule.QueryResultsRow row : results ) {
names.add( ((Person) row.get( "$p" )).getName() );
}
assertEquals( 4,
names.size() );
assertTrue( names.contains( "luke" ) );
assertTrue( names.contains( "yoda" ) );
assertTrue( names.contains( "bobba" ) );
assertTrue( names.contains( "darth" ) );
results = getQueryResults(ksession, "peeps", new Object[]{Variable.v, Variable.v, 300} );
assertEquals( 3, results.size() );
names = new ArrayList();
for ( org.kie.api.runtime.rule.QueryResultsRow row : results ) {
names.add( ((Person) row.get( "$p" )).getName() );
}
assertEquals( 3,
names.size() );
assertTrue( names.contains( "luke" ) );
assertTrue( names.contains( "yoda" ) );
assertTrue( names.contains( "bobba" ) );
results = getQueryResults(ksession, "peeps", new Object[]{Variable.v, "stilton", 300} );
assertEquals( 1, results.size() );
names = new ArrayList();
for ( org.kie.api.runtime.rule.QueryResultsRow row : results ) {
names.add( ((Person) row.get( "$p" )).getName() );
}
assertEquals( 1,
names.size() );
assertTrue( names.contains( "yoda" ) );
results = ksession.getQueryResults( "peeps",
new Object[]{Variable.v, "stilton", Variable.v} );
assertEquals( 2,
results.size() );
names = new ArrayList();
for ( org.kie.api.runtime.rule.QueryResultsRow row : results ) {
names.add( ((Person) row.get( "$p" )).getName() );
}
assertEquals( 2,
names.size() );
assertTrue( names.contains( "yoda" ) );
assertTrue( names.contains( "darth" ) );
results = ksession.getQueryResults( "peeps",
new Object[]{"darth", Variable.v, Variable.v} );
assertEquals( 1,
results.size() );
names = new ArrayList();
for ( org.kie.api.runtime.rule.QueryResultsRow row : results ) {
names.add( ((Person) row.get( "$p" )).getName() );
}
assertEquals( 1,
names.size() );
assertTrue( names.contains( "darth" ) );
}
@Test
public void testQueriesWithVariableUnificationOnPatterns() throws Exception {
String str = "";
str += "package org.drools.compiler.test \n";
str += "import org.drools.compiler.Person \n";
str += "query peeps( Person $p, String $name, String $likes, int $age ) \n";
str += " $p := Person( $name := name, $likes := likes, $age := age ) \n";
str += "end\n";
KieBase kbase = SerializationHelper.serializeObject(loadKnowledgeBaseFromString(str));
KieSession ksession = createKieSession( kbase );
Person p1 = new Person( "darth",
"stilton",
100 );
Person p2 = new Person( "yoda",
"stilton",
300 );
Person p3 = new Person( "luke",
"brie",
300 );
Person p4 = new Person( "bobba",
"cheddar",
300 );
ksession.insert( p1 );
ksession.insert( p2 );
ksession.insert( p3 );
ksession.insert( p4 );
org.kie.api.runtime.rule.QueryResults results = ksession.getQueryResults( "peeps",
new Object[]{Variable.v, Variable.v, Variable.v, Variable.v} );
assertEquals( 4,
results.size() );
List names = new ArrayList();
for ( org.kie.api.runtime.rule.QueryResultsRow row : results ) {
names.add( ((Person) row.get( "$p" )).getName() );
}
assertEquals( 4,
names.size() );
assertTrue( names.contains( "luke" ) );
assertTrue( names.contains( "yoda" ) );
assertTrue( names.contains( "bobba" ) );
assertTrue( names.contains( "darth" ) );
results = ksession.getQueryResults( "peeps",
new Object[]{p1, Variable.v, Variable.v, Variable.v} );
assertEquals( 1,
results.size() );
names = new ArrayList();
for ( org.kie.api.runtime.rule.QueryResultsRow row : results ) {
names.add( ((Person) row.get( "$p" )).getName() );
}
assertEquals( 1,
names.size() );
assertTrue( names.contains( "darth" ) );
}
@Test
public void testQueriesWithVariableUnificationOnNestedFields() throws Exception {
String str = "";
str += "package org.drools.compiler.test \n";
str += "import org.drools.compiler.Person \n";
str += "query peeps( String $name, String $likes, String $street) \n";
str += " $p : Person( $name := name, $likes := likes, $street := address.street ) \n";
str += "end\n";
KieBase kbase = SerializationHelper.serializeObject(loadKnowledgeBaseFromString(str));
KieSession ksession = createKieSession( kbase );
Person p1 = new Person( "darth",
"stilton",
100 );
p1.setAddress( new Address( "s1" ) );
Person p2 = new Person( "yoda",
"stilton",
300 );
p2.setAddress( new Address( "s2" ) );
ksession.insert( p1 );
ksession.insert( p2 );
QueryResults results = getQueryResults( ksession, "peeps", new Object[]{Variable.v, Variable.v, Variable.v} );
assertEquals( 2,
results.size() );
List names = new ArrayList();
for ( org.kie.api.runtime.rule.QueryResultsRow row : results ) {
names.add( ((Person) row.get( "$p" )).getName() );
}
assertTrue( names.contains( "yoda" ) );
assertTrue( names.contains( "darth" ) );
results = getQueryResults( ksession, "peeps", new Object[]{Variable.v, Variable.v, "s1"} );
assertEquals( 1,
results.size() );
names = new ArrayList();
for ( org.kie.api.runtime.rule.QueryResultsRow row : results ) {
names.add( ((Person) row.get( "$p" )).getName() );
}
assertTrue( names.contains( "darth" ) );
}
@Test
public void testOpenQuery() throws Exception {
String str = "";
str += "package org.drools.compiler.test \n";
str += "import org.drools.compiler.Cheese \n";
str += "query cheeses(String $type1, String $type2) \n";
str += " stilton : Cheese(type == $type1, $sprice : price) \n";
str += " cheddar : Cheese(type == $type2, $cprice : price == stilton.price) \n";
str += "end\n";
KieBase kbase = SerializationHelper.serializeObject(loadKnowledgeBaseFromString(str));
KieSession ksession = createKieSession( kbase );
Cheese stilton1 = new Cheese( "stilton",
1 );
Cheese cheddar1 = new Cheese( "cheddar",
1 );
Cheese stilton2 = new Cheese( "stilton",
2 );
Cheese cheddar2 = new Cheese( "cheddar",
2 );
Cheese stilton3 = new Cheese( "stilton",
3 );
Cheese cheddar3 = new Cheese( "cheddar",
3 );
FactHandle s1Fh = ksession.insert( stilton1 );
ksession.insert( stilton2 );
ksession.insert( stilton3 );
ksession.insert( cheddar1 );
ksession.insert( cheddar2 );
FactHandle c3Fh = ksession.insert( cheddar3 );
final List<Object[]> updated = new ArrayList<Object[]>();
final List<Object[]> removed = new ArrayList<Object[]>();
final List<Object[]> added = new ArrayList<Object[]>();
ViewChangedEventListener listener = new ViewChangedEventListener() {
public void rowUpdated( Row row ) {
Object[] array = new Object[6];
array[0] = row.get( "stilton" );
array[1] = row.get( "cheddar" );
array[2] = row.get( "$sprice" );
array[3] = row.get( "$cprice" );
array[4] = row.get( "$type1" );
array[5] = row.get( "$type2" );
updated.add( array );
}
public void rowDeleted( Row row ) {
Object[] array = new Object[6];
array[0] = row.get( "stilton" );
array[1] = row.get( "cheddar" );
array[2] = row.get( "$sprice" );
array[3] = row.get( "$cprice" );
array[4] = row.get( "$type1" );
array[5] = row.get( "$type2" );
removed.add( array );
}
public void rowInserted( Row row ) {
Object[] array = new Object[6];
array[0] = row.get( "stilton" );
array[1] = row.get( "cheddar" );
array[2] = row.get( "$sprice" );
array[3] = row.get( "$cprice" );
array[4] = row.get( "$type1" );
array[5] = row.get( "$type2" );
added.add( array );
}
};
// Open the LiveQuery
LiveQuery query = ksession.openLiveQuery( "cheeses",
new Object[]{"stilton", "cheddar"},
listener );
ksession.fireAllRules();
// Assert that on opening we have three rows added
assertEquals( 3,
added.size() );
assertEquals( 0,
removed.size() );
assertEquals( 0,
updated.size() );
// Assert that the identifiers where retrievable
assertSame( stilton1,
added.get( 2 )[0] );
assertSame( cheddar1,
added.get( 2 )[1] );
assertEquals( 1,
added.get( 2 )[2] );
assertEquals( 1,
added.get( 2 )[3] );
assertEquals( "stilton",
added.get( 2 )[4] );
assertEquals( "cheddar",
added.get( 2 )[5] );
// And that we have correct values from those rows
assertEquals( 3,
added.get( 0 )[3] );
assertEquals( 2,
added.get( 1 )[3] );
assertEquals( 1,
added.get( 2 )[3] );
// Do an update that causes a match to become untrue, thus triggering a removed
cheddar3.setPrice( 4 );
ksession.update( c3Fh,
cheddar3 );
ksession.fireAllRules();
assertEquals( 3,
added.size() );
assertEquals( 1,
removed.size() );
assertEquals( 0,
updated.size() );
assertEquals( 4,
removed.get( 0 )[3] );
// Now make that partial true again, and thus another added
cheddar3.setPrice( 3 );
ksession.update( c3Fh,
cheddar3 );
ksession.fireAllRules();
assertEquals( 4,
added.size() );
assertEquals( 1,
removed.size() );
assertEquals( 0,
updated.size() );
assertEquals( 3,
added.get( 3 )[3] );
// check a standard update
cheddar3.setOldPrice( 0 );
ksession.update( c3Fh,
cheddar3 );
ksession.fireAllRules();
assertEquals( 4,
added.size() );
assertEquals( 1,
removed.size() );
assertEquals( 1,
updated.size() );
assertEquals( 3,
updated.get( 0 )[3] );
// Check a standard retract
ksession.retract( s1Fh );
ksession.fireAllRules();
assertEquals( 4,
added.size() );
assertEquals( 2,
removed.size() );
assertEquals( 1,
updated.size() );
assertEquals( 1,
removed.get( 1 )[3] );
// Close the query, we should get removed events for each row
query.close();
ksession.fireAllRules();
assertEquals( 4,
added.size() );
assertEquals( 4,
removed.size() );
assertEquals( 1,
updated.size() );
assertEquals( 2,
removed.get( 3 )[3] );
assertEquals( 3,
removed.get( 2 )[3] );
// Check that updates no longer have any impact.
ksession.update( c3Fh,
cheddar3 );
assertEquals( 4,
added.size() );
assertEquals( 4,
removed.size() );
assertEquals( 1,
updated.size() );
}
@Test
public void testStandardQueryListener() throws IOException, ClassNotFoundException {
runQueryListenerTest( QueryListenerOption.STANDARD );
}
@Test
public void testNonCloningQueryListener() throws IOException, ClassNotFoundException {
runQueryListenerTest( QueryListenerOption.LIGHTWEIGHT );
}
public void runQueryListenerTest( QueryListenerOption option ) throws IOException, ClassNotFoundException {
String str = "";
str += "package org.drools.compiler.integrationtests\n";
str += "import " + Cheese.class.getCanonicalName() + " \n";
str += "query cheeses(String $type) \n";
str += " $cheese : Cheese(type == $type) \n";
str += "end\n";
KieBase kbase = SerializationHelper.serializeObject(loadKnowledgeBaseFromString(str));
KieSession ksession = createKieSession( kbase, option );
// insert some data into the session
for ( int i = 0; i < 10000; i++ ) {
ksession.insert( new Cheese( i % 2 == 0 ? "stilton" : "brie" ) );
}
// query the session
List<Cheese> cheeses;
for ( int i = 0; i < 100; i++ ) {
org.kie.api.runtime.rule.QueryResults queryResults = ksession.getQueryResults( "cheeses",
new Object[]{"stilton"} );
cheeses = new ArrayList<Cheese>();
for ( QueryResultsRow row : queryResults ) {
cheeses.add( (Cheese) row.get( "$cheese" ) );
}
assertEquals( 5000,
cheeses.size() );
}
}
@Test
public void testQueryWithEval() throws IOException, ClassNotFoundException {
// [Regression in 5.2.0.M2]: NPE during rule evaluation on MVELPredicateExpression.evaluate(MVELPredicateExpression.java:82)
String str = "package org.drools.compiler.integrationtests\n" +
"import " + DomainObject.class.getCanonicalName() + " \n" +
"query queryWithEval \n" +
" $do: DomainObject()\n" +
" not DomainObject( id == $do.id, eval(interval.isAfter($do.getInterval())))\n" +
"end";
KieBase kbase = SerializationHelper.serializeObject(loadKnowledgeBaseFromString(str));
KieSession ksession = createKieSession( kbase );
DomainObject do1 = new DomainObject();
do1.setId( 1 );
do1.setInterval( new Interval( 10,
5 ) );
DomainObject do2 = new DomainObject();
do2.setId( 1 );
do2.setInterval( new Interval( 20,
5 ) );
ksession.insert( do1 );
ksession.insert( do2 );
org.kie.api.runtime.rule.QueryResults results = ksession.getQueryResults( "queryWithEval" );
assertEquals( 1,
results.size() );
assertEquals( do2,
results.iterator().next().get( "$do" ) );
ksession.dispose();
}
@Test
public void testQueryWithIncompatibleArgs() {
String drl = "global java.util.List list; " +
"" +
"query foo( String $s, String $s, String $s ) end " +
"" +
"rule React \n" +
"when\n" +
" $i : Integer() " +
" foo( $i, $x, $i ; ) " +
"then\n" +
"end";
KieHelper helper = new KieHelper();
helper.addContent( drl, ResourceType.DRL );
Results results = helper.verify();
assertTrue( results.hasMessages( Message.Level.ERROR ) );
assertEquals( 2, results.getMessages( Message.Level.ERROR ).size() );
}
@Test
public void testQueryWithSyntaxError() {
String drl = "global java.util.List list; " +
"" +
"query foo( Integer $i ) end " +
"" +
"rule React \n" +
"when\n" +
" $i : Integer() " +
" foo( $i ) " + // missing ";" should result in 1 compilation error
"then\n" +
"end";
KieHelper helper = new KieHelper();
helper.addContent( drl, ResourceType.DRL );
Results results = helper.verify();
assertTrue( results.hasMessages( Message.Level.ERROR ) );
assertEquals( 1, results.getMessages( Message.Level.ERROR ).size() );
}
@Test
public void testQueryWithWrongParamNumber() {
String drl = "global java.util.List list; " +
"" +
"query foo( Integer $i ) end " +
"" +
"rule React \n" +
"when\n" +
" $i : Integer() " +
" $j : Integer() " +
" foo( $i, $j ; ) " +
"then\n" +
"end";
KieHelper helper = new KieHelper();
helper.addContent( drl, ResourceType.DRL );
Results results = helper.verify();
assertTrue( results.hasMessages( Message.Level.ERROR ) );
assertEquals( 1, results.getMessages( Message.Level.ERROR ).size() );
}
@Test
public void testGlobalsInQueries() {
String drl = "\n" +
"package com.sample\n" +
"\n" +
"global java.lang.String AString;\n" +
"global java.util.List list;\n" +
"\n" +
"declare AThing\n" +
" name: String @key\n" +
"end\n" +
"\n" +
"rule init\n" +
" when\n" +
" then\n" +
" insert( new AThing( AString ) );\n" +
" insert( new AThing( 'Holla' ) );\n" +
"end\n" +
"\n" +
"query test( String $in ) \n" +
" AThing( $in; )\n" +
"end\n" +
"\n" +
"rule spot\n" +
" when\n" +
" test( \"Hello\"; )\n" +
" AThing( \"Hello\"; )\n" +
" test( AString; )\n" +
" AThing( AString; )" +
" then\n" +
" list.add( AString + \" World\" );\n" +
"end\n";
KieHelper helper = new KieHelper();
helper.addContent( drl, ResourceType.DRL );
KieSession ks = helper.build( ).newKieSession();
ArrayList list = new ArrayList();
ks.setGlobal( "AString", "Hello" );
ks.setGlobal( "list", list );
ks.fireAllRules();
assertEquals( Arrays.asList( "Hello World" ), list );
}
@Test
public void testQueryWithClassArg() {
//DROOLS-590
String drl = "global java.util.List list; " +
"" +
"declare Foo end " +
"" +
"query bar( Class $c ) " +
" Class( this.getName() == $c.getName() ) " +
"end " +
"query bar2( Class $c ) " +
" Class( this == $c ) " +
"end " +
"" +
"rule Init when then insert( Foo.class ); end " +
"" +
"rule React1 " +
"when " +
" bar( Foo.class ; ) " +
"then " +
" list.add( 'aa' ); " +
"end " +
"rule React2 " +
"when\n" +
" bar2( Foo.class ; ) " +
"then " +
" list.add( 'bb' ); " +
"end";
List list = new ArrayList( );
KieHelper helper = new KieHelper();
helper.addContent( drl, ResourceType.DRL );
KieSession ks = helper.build( ).newKieSession();
ks.setGlobal( "list", list );
ks.fireAllRules();
assertEquals( Arrays.asList( "aa", "bb" ), list );
}
@Test
public void testPassGlobalToNestedQuery() {
// DROOLS-851
String drl = "global java.util.List list;\n" +
"global Integer number;\n" +
"\n" +
"query findString( String $out )\n" +
" findStringWithLength( number, $out; )\n" +
"end\n" +
"query findStringWithLength( int $in, String $out )\n" +
" $out := String( $in := length )\n" +
"end\n" +
"\n" +
"rule R when\n" +
" findString( $s; )\n" +
"then\n" +
" list.add( $s );\n" +
"end\n";
KieHelper helper = new KieHelper();
helper.addContent( drl, ResourceType.DRL );
KieSession ks = helper.build( ).newKieSession();
ArrayList list = new ArrayList();
ks.setGlobal( "list", list );
ks.setGlobal( "number", 3 );
ks.insert( "Hi" );
ks.insert( "Bye" );
ks.insert( "Hello" );
ks.fireAllRules();
assertEquals( Arrays.asList( "Bye" ), list );
}
@Test
public void testQueryWithAccessorAsArgument() throws Exception {
// DROOLS-414
String str =
"import org.drools.compiler.Person\n" +
"global java.util.List persons;\n" +
"\n" +
"query contains(String $s, String $c)\n" +
" $s := String( this.contains( $c ) )\n" +
"end\n" +
"\n" +
"rule R when\n" +
" $p : Person()\n" +
" contains( $p.name, \"a\"; )\n" +
"then\n" +
" persons.add( $p );\n" +
"end\n";
KieHelper helper = new KieHelper();
helper.addContent( str, ResourceType.DRL );
KieSession ksession = helper.build().newKieSession();
List<Person> personsWithA = new ArrayList<Person>();
ksession.setGlobal("persons", personsWithA);
ksession.insert("Mark");
ksession.insert("Edson");
ksession.insert("Mario");
ksession.insert(new Person("Mark"));
ksession.insert(new Person("Edson"));
ksession.insert(new Person("Mario"));
ksession.fireAllRules();
assertEquals(2, personsWithA.size());
for (Person p : personsWithA) {
assertTrue( p.getName().equals( "Mark" ) || p.getName().equals( "Mario" ) );
}
}
@Test
public void testQueryWithExpressionAsArgument() throws Exception {
// DROOLS-414
String str =
"import org.drools.compiler.Person\n" +
"global java.util.List persons;\n" +
"\n" +
"query checkLength(String $s, int $l)\n" +
" $s := String( length == $l )\n" +
"end\n" +
"\n" +
"rule R when\n" +
" $i : Integer()\n" +
" $p : Person()\n" +
" checkLength( $p.name, 1 + $i + $p.age; )\n" +
"then\n" +
" persons.add( $p );\n" +
"end\n";
KieHelper helper = new KieHelper();
helper.addContent( str, ResourceType.DRL );
KieSession ksession = helper.build().newKieSession();
List<Person> list = new ArrayList<Person>();
ksession.setGlobal("persons", list);
ksession.insert(1);
ksession.insert("Mark");
ksession.insert("Edson");
ksession.insert("Mario");
ksession.insert(new Person("Mark", 2));
ksession.insert(new Person("Edson", 3));
ksession.insert(new Person("Mario", 4));
ksession.fireAllRules();
System.out.println(list);
assertEquals(2, list.size());
for (Person p : list) {
assertTrue( p.getName().equals( "Mark" ) || p.getName().equals( "Edson" ) );
}
}
@Test
public void testNotExistingDeclarationInQuery() {
// DROOLS-414
String drl =
"import org.drools.compiler.Person\n" +
"global java.util.List persons;\n" +
"\n" +
"query checkLength(String $s, int $l)\n" +
" $s := String( length == $l )\n" +
"end\n" +
"\n" +
"rule R when\n" +
" $i : Integer()\n" +
" $p : Person()\n" +
" checkLength( $p.name, 1 + $x + $p.age; )\n" +
"then\n" +
" persons.add( $p );\n" +
"end\n";
KieServices ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem().write( "src/main/resources/r1.drl", drl );
Results results = ks.newKieBuilder( kfs ).buildAll().getResults();
assertFalse( results.getMessages().isEmpty() );
}
}