/*
* Copyright 2011 Red Hat Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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.persistence.session;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Random;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.drools.core.common.DefaultFactHandle;
import org.drools.persistence.api.PersistenceContextManager;
import org.drools.persistence.util.DroolsPersistenceUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.kie.api.KieBase;
import org.kie.api.event.rule.DefaultAgendaEventListener;
import org.kie.api.event.rule.DefaultRuleRuntimeEventListener;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.Environment;
import org.kie.api.runtime.EnvironmentName;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;
import org.kie.internal.KnowledgeBase;
import org.kie.internal.KnowledgeBaseFactory;
import org.kie.internal.builder.KnowledgeBuilder;
import org.kie.internal.builder.KnowledgeBuilderFactory;
import org.kie.internal.io.ResourceFactory;
import org.kie.internal.persistence.jpa.JPAKnowledgeService;
import org.kie.internal.runtime.StatefulKnowledgeSession;
import static org.drools.persistence.util.DroolsPersistenceUtil.*;
import static org.junit.Assert.*;
import static org.kie.api.runtime.EnvironmentName.ENTITY_MANAGER_FACTORY;
@RunWith(Parameterized.class)
public class ReloadSessionTest {
// Datasource (setup & clean up)
private Map<String, Object> context;
private EntityManagerFactory emf;
private boolean locking;
private static final String ENTRY_POINT = "ep1";
private static String simpleRule =
"package org.kie.test\n"
+ "global java.util.List list\n"
+ "rule rule1\n"
+ "when\n"
+ " Integer(intValue > 0)\n"
+ "then\n"
+ " list.add( 1 );\n"
+ "end\n"
+ "\n";
private static final String RULE_WITH_EP =
"package org.kie.test\n"
+ "global java.util.List list\n"
+ "rule rule1\n"
+ "when\n"
+ " Integer(intValue > 0) from entry-point " + ENTRY_POINT + " \n"
+ "then\n"
+ " list.add( 1 );\n"
+ "end\n"
+ "\n";
@Parameters(name="{0}")
public static Collection<Object[]> persistence() {
Object[][] locking = new Object[][] {
{ OPTIMISTIC_LOCKING },
{ PESSIMISTIC_LOCKING }
};
return Arrays.asList(locking);
};
public ReloadSessionTest(String locking) {
this.locking = PESSIMISTIC_LOCKING.equals(locking);
}
@Before
public void setup() {
context = DroolsPersistenceUtil.setupWithPoolingDataSource(DROOLS_PERSISTENCE_UNIT_NAME);
emf = (EntityManagerFactory) context.get(ENTITY_MANAGER_FACTORY);
}
@After
public void cleanUp() {
DroolsPersistenceUtil.cleanUp(context);
}
private Environment createEnvironment() {
Environment env = DroolsPersistenceUtil.createEnvironment(context);
if( locking ) {
env.set(EnvironmentName.USE_PESSIMISTIC_LOCKING, true);
}
return env;
}
private KnowledgeBase initializeKnowledgeBase(String rule) {
// Initialize knowledge base/session/etc..
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newByteArrayResource(rule.getBytes()), ResourceType.DRL);
if (kbuilder.hasErrors()) {
fail(kbuilder.getErrors().toString());
}
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
return kbase;
}
@Test
public void reloadKnowledgeSessionTest() {
// Initialize drools environment stuff
Environment env = createEnvironment();
KnowledgeBase kbase = initializeKnowledgeBase(simpleRule);
StatefulKnowledgeSession commandKSession = JPAKnowledgeService.newStatefulKnowledgeSession( kbase, null, env );
assertTrue("There should be NO facts present in a new (empty) knowledge session.", commandKSession.getFactHandles().isEmpty());
// Persist a facthandle to the database
Integer integerFact = (new Random()).nextInt(Integer.MAX_VALUE-1) + 1;
commandKSession.insert( integerFact );
// At this point in the code, the fact has been persisted to the database
// (within a transaction via the PersistableRunner)
Collection<FactHandle> factHandles = commandKSession.getFactHandles();
assertTrue("At least one fact should have been inserted by the ksession.insert() method above.", !factHandles.isEmpty());
FactHandle origFactHandle = factHandles.iterator().next();
assertTrue("The stored fact should contain the same number as the value inserted (but does not).",
Integer.parseInt(((DefaultFactHandle) origFactHandle).getObject().toString()) == integerFact.intValue() );
// Save the sessionInfo id in order to retrieve it later
long sessionInfoId = commandKSession.getIdentifier();
// Clean up the session, environment, etc.
PersistenceContextManager pcm = (PersistenceContextManager) commandKSession.getEnvironment().get(EnvironmentName.PERSISTENCE_CONTEXT_MANAGER);
commandKSession.dispose();
pcm.dispose();
emf.close();
// Reload session from the database
emf = Persistence.createEntityManagerFactory(DROOLS_PERSISTENCE_UNIT_NAME);
context.put(ENTITY_MANAGER_FACTORY, emf);
env = createEnvironment();
// Re-initialize the knowledge session:
StatefulKnowledgeSession newCommandKSession
= JPAKnowledgeService.loadStatefulKnowledgeSession(sessionInfoId, kbase, null, env);
// Test that the session has been successfully reinitialized
factHandles = newCommandKSession.getFactHandles();
assertTrue("At least one fact should have been persisted by the ksession.insert above.",
!factHandles.isEmpty() && factHandles.size() == 1);
FactHandle retrievedFactHandle = factHandles.iterator().next();
assertTrue("If the retrieved and original FactHandle object are the same, then the knowledge session has NOT been reloaded!",
origFactHandle != retrievedFactHandle);
assertTrue("The retrieved fact should contain the same info as the original (but does not).",
Integer.parseInt(((DefaultFactHandle) retrievedFactHandle).getObject().toString()) == integerFact.intValue() );
// Test to see if the (retrieved) facts can be processed
ArrayList<Object>list = new ArrayList<Object>();
newCommandKSession.setGlobal( "list", list );
newCommandKSession.fireAllRules();
assertEquals( 1, list.size() );
}
@Test @Ignore
public void testListenersAfterSessionReload() {
// https://bugzilla.redhat.com/show_bug.cgi?id=826952
Environment env = createEnvironment();
KnowledgeBase kbase = initializeKnowledgeBase(simpleRule);
StatefulKnowledgeSession ksession = JPAKnowledgeService.newStatefulKnowledgeSession( kbase, null, env );
ksession.addEventListener(new DefaultAgendaEventListener());
ksession.addEventListener(new DefaultRuleRuntimeEventListener());
assertEquals(1, ksession.getRuleRuntimeEventListeners().size());
assertEquals(1, ksession.getAgendaEventListeners().size());
ksession = JPAKnowledgeService.loadStatefulKnowledgeSession(ksession.getIdentifier(), kbase, null, env);
assertEquals(1, ksession.getRuleRuntimeEventListeners().size());
assertEquals(1, ksession.getAgendaEventListeners().size());
}
@Test
public void testInsert() {
final Environment env = createEnvironment();
final KieBase kbase = initializeKnowledgeBase( RULE_WITH_EP );
KieSession kieSession = JPAKnowledgeService.newStatefulKnowledgeSession( kbase, null, env );
assertTrue("There should be NO facts present in a new (empty) knowledge session.", kieSession.getFactHandles().isEmpty());
kieSession.insert(Integer.valueOf(10));
kieSession = reloadSession(kieSession, env);
Collection<? extends Object> objects = kieSession.getObjects();
assertEquals("Reloaded working memory should contain the fact.", 1, objects.size());
}
@Test
public void testInsertIntoEntryPoint() {
// RHBRMS-2815
final Environment env = createEnvironment();
final KieBase kbase = initializeKnowledgeBase(RULE_WITH_EP);
KieSession kieSession = JPAKnowledgeService.newStatefulKnowledgeSession(kbase, null, env);
assertTrue("There should be NO facts present in a new (empty) knowledge session.", kieSession.getFactHandles().isEmpty());
kieSession.getEntryPoint(ENTRY_POINT).insert(Integer.valueOf(10));
kieSession = reloadSession(kieSession, env);
Collection<? extends Object> objects = kieSession.getEntryPoint(ENTRY_POINT).getObjects();
assertEquals("Reloaded working memory should contain the fact in the entry point.", 1, objects.size());
}
private KieSession reloadSession(final KieSession kieSession, final Environment environment) {
final long sessionId = kieSession.getIdentifier();
final KieBase kieBase = kieSession.getKieBase();
kieSession.dispose();
return JPAKnowledgeService.loadStatefulKnowledgeSession(sessionId, kieBase, null, environment);
}
}