4450b8c8dfb76b3e51d4b3c8272f048b82c00320
[policy/drools-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * feature-session-persistence
4  * ================================================================================
5  * Copyright (C) 2017-2018, 2020-2021 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.drools.persistence;
22
23 import static org.assertj.core.api.Assertions.assertThatCode;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertFalse;
26 import static org.junit.Assert.assertNotNull;
27 import static org.junit.Assert.assertNull;
28 import static org.junit.Assert.assertTrue;
29 import static org.junit.Assert.fail;
30 import static org.mockito.ArgumentMatchers.any;
31 import static org.mockito.ArgumentMatchers.anyLong;
32 import static org.mockito.ArgumentMatchers.anyString;
33 import static org.mockito.Mockito.doThrow;
34 import static org.mockito.Mockito.mock;
35 import static org.mockito.Mockito.never;
36 import static org.mockito.Mockito.times;
37 import static org.mockito.Mockito.verify;
38 import static org.mockito.Mockito.when;
39
40 import java.io.FileNotFoundException;
41 import java.io.FileReader;
42 import java.io.IOException;
43 import java.sql.Connection;
44 import java.sql.DriverManager;
45 import java.sql.PreparedStatement;
46 import java.sql.ResultSet;
47 import java.sql.SQLException;
48 import java.sql.Timestamp;
49 import java.util.ArrayList;
50 import java.util.List;
51 import java.util.Map;
52 import java.util.Properties;
53 import java.util.concurrent.CountDownLatch;
54 import java.util.concurrent.TimeUnit;
55 import javax.persistence.EntityManager;
56 import javax.persistence.EntityManagerFactory;
57 import javax.transaction.TransactionManager;
58 import javax.transaction.TransactionSynchronizationRegistry;
59 import javax.transaction.UserTransaction;
60 import org.apache.commons.dbcp2.BasicDataSource;
61 import org.junit.After;
62 import org.junit.Before;
63 import org.junit.BeforeClass;
64 import org.junit.Test;
65 import org.kie.api.KieBase;
66 import org.kie.api.KieServices;
67 import org.kie.api.persistence.jpa.KieStoreServices;
68 import org.kie.api.runtime.Environment;
69 import org.kie.api.runtime.EnvironmentName;
70 import org.kie.api.runtime.KieContainer;
71 import org.kie.api.runtime.KieSession;
72 import org.kie.api.runtime.KieSessionConfiguration;
73 import org.mockito.ArgumentCaptor;
74 import org.onap.policy.drools.core.PolicyContainer;
75 import org.onap.policy.drools.core.PolicySession;
76 import org.onap.policy.drools.core.PolicySession.ThreadModel;
77 import org.onap.policy.drools.persistence.PersistenceFeature.PersistenceFeatureException;
78 import org.onap.policy.drools.persistence.PersistenceFeature.PersistentThreadModel;
79 import org.onap.policy.drools.system.PolicyController;
80 import org.slf4j.Logger;
81 import org.slf4j.LoggerFactory;
82
83 public class PersistenceFeatureTest {
84
85     private static final String MY_KIE_BASE = "mybase";
86
87     private static final String MY_SESS_NAME = "myname";
88
89     private static final String MISSING_EXCEPTION = "missing exception";
90
91     private static final String EXPECTED = "expected exception";
92
93     private static final Logger logger = LoggerFactory.getLogger(PersistenceFeatureTest.class);
94
95     private static final String JDBC_DRIVER = "fake.driver";
96     private static final String JDBC_URL = "fake.url";
97     private static final String JDBC_USER = "fake.user";
98     private static final String JDBC_PASSWD = "fake.password";
99     private static final String JTA_OSDIR = "target";
100     private static final String SRC_TEST_RESOURCES = "src/test/resources";
101
102     private static Properties stdprops;
103
104     private JpaDroolsSessionConnector jpa;
105     private DroolsSession sess;
106     private KieSession kiesess;
107     private BasicDataSource bds;
108     private EntityManagerFactory emf;
109     private Connection conn;
110     private Properties props;
111     private KieServices kiesvc;
112     private Environment kieenv;
113     private KieSessionConfiguration kiecfg;
114     private KieBase kiebase;
115     private KieStoreServices kiestore;
116     private TransactionManager transmgr;
117     private UserTransaction usertrans;
118     private TransactionSynchronizationRegistry transreg;
119     private PolicyController polctlr;
120     private PolicyContainer polcont;
121     private PolicySession polsess;
122     private int emfCount;
123     private int jpaCount;
124     private String propName;
125
126     private PersistenceFeature feat;
127
128     /**
129      * Setup before class.
130      *
131      * @throws Exception exception
132      */
133     @BeforeClass
134     public static void setUpBeforeClass() throws Exception {
135         stdprops = new Properties();
136
137         stdprops.put(DroolsPersistenceProperties.DB_DRIVER, JDBC_DRIVER);
138         stdprops.put(DroolsPersistenceProperties.DB_URL, JDBC_URL);
139         stdprops.put(DroolsPersistenceProperties.DB_USER, JDBC_USER);
140         stdprops.put(DroolsPersistenceProperties.DB_PWD, JDBC_PASSWD);
141         stdprops.put(DroolsPersistenceProperties.JTA_OBJECTSTORE_DIR, JTA_OSDIR);
142         stdprops.put(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT, "50");
143
144         System.setProperty("com.arjuna.ats.arjuna.objectstore.objectStoreDir", "target/tm");
145         System.setProperty("ObjectStoreEnvironmentBean.objectStoreDir", "target/tm");
146     }
147
148     /**
149      * Setup.
150      *
151      * @throws Exception exception
152      */
153     @Before
154     public void setUp() throws Exception {
155         jpa = mock(JpaDroolsSessionConnector.class);
156         sess = mock(DroolsSession.class);
157         bds = mock(BasicDataSource.class);
158         emf = mock(EntityManagerFactory.class);
159         kiesess = mock(KieSession.class);
160         conn = null;
161         props = new Properties();
162         kiesvc = mock(KieServices.class);
163         kieenv = mock(Environment.class);
164         kiecfg = mock(KieSessionConfiguration.class);
165         kiebase = mock(KieBase.class);
166         kiestore = mock(KieStoreServices.class);
167         transmgr = mock(TransactionManager.class);
168         usertrans = mock(UserTransaction.class);
169         transreg = mock(TransactionSynchronizationRegistry.class);
170         polcont = mock(PolicyContainer.class);
171         polctlr = mock(PolicyController.class);
172         polsess = mock(PolicySession.class);
173         emfCount = 0;
174         jpaCount = 0;
175         propName = null;
176
177         feat = new PersistenceFeatureImpl();
178
179         props.putAll(stdprops);
180
181         System.setProperty("com.arjuna.ats.arjuna.objectstore.objectStoreDir", "target/tm");
182         System.setProperty("ObjectStoreEnvironmentBean.objectStoreDir", "target/tm");
183
184         when(kiesvc.newEnvironment()).thenReturn(kieenv);
185         when(kiesvc.getStoreServices()).thenReturn(kiestore);
186         when(kiesvc.newKieSessionConfiguration()).thenReturn(kiecfg);
187
188         KieContainer kiecont = mock(KieContainer.class);
189         when(polcont.getKieContainer()).thenReturn(kiecont);
190
191         when(polsess.getContainer()).thenReturn(polcont);
192
193         when(kiecont.getKieBase(anyString())).thenReturn(kiebase);
194     }
195
196     /**
197      * Tear down.
198      */
199     @After
200     public void tearDown() {
201         // this will cause the in-memory test DB to be dropped
202         if (conn != null) {
203             try {
204                 conn.close();
205             } catch (SQLException e) {
206                 logger.warn("failed to close connection", e);
207             }
208         }
209
210         if (emf != null) {
211             try {
212                 emf.close();
213             } catch (IllegalArgumentException e) {
214                 logger.trace("ignored exception", e);
215             }
216         }
217     }
218
219     @Test
220     public void testGetContainerAdjunct_New() throws Exception {
221         setUpKie(MY_SESS_NAME, 999L, true);
222         mockDbConn(5);
223
224         // force getContainerAdjunct() to be invoked
225         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
226
227         ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
228                 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
229
230         verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
231
232         assertNotNull(adjcap.getValue());
233     }
234
235     @Test
236     public void testGetContainerAdjunct_Existing() throws Exception {
237         setUpKie(MY_SESS_NAME, 999L, true);
238         mockDbConn(5);
239
240         // force getContainerAdjunct() to be invoked
241         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
242
243         ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
244                 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
245
246         verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
247
248         // return adjunct on next call
249         when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
250
251         // force getContainerAdjunct() to be invoked again
252         setUpKie("myname2", 999L, true);
253         mockDbConn(5);
254         feat.activatePolicySession(polcont, "myname2", MY_KIE_BASE);
255
256         // ensure it isn't invoked again
257         verify(polcont, times(1)).setAdjunct(any(), any());
258     }
259
260     @Test
261     public void testGetContainerAdjunct_WrongType() throws Exception {
262         setUpKie(MY_SESS_NAME, 999L, true);
263         mockDbConn(5);
264
265         // return false adjunct on next call
266         when(polcont.getAdjunct(any())).thenReturn("not-a-real-adjunct");
267
268         // force getContainerAdjunct() to be invoked
269         setUpKie("myname2", 999L, true);
270         mockDbConn(5);
271         feat.activatePolicySession(polcont, "myname2", MY_KIE_BASE);
272
273         ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
274                 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
275
276         verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
277
278         assertNotNull(adjcap.getValue());
279     }
280
281     @Test
282     public void testGetSequenceNumber() {
283         assertEquals(1, feat.getSequenceNumber());
284     }
285
286     @Test
287     public void testGlobalInit() throws Exception {
288
289         feat.globalInit(null, SRC_TEST_RESOURCES);
290
291         // verify that various factory methods were invoked
292         assertEquals("src/test/resources/feature-session-persistence.properties", propName);
293     }
294
295     @Test(expected = NullPointerException.class)
296     public void testGlobalInitIoEx() throws Exception {
297
298         feat = new PersistenceFeatureImpl() {
299             @Override
300             protected Properties loadProperties(String filenm) throws IOException {
301                 throw new IOException(EXPECTED);
302             }
303         };
304
305         feat.globalInit(null, SRC_TEST_RESOURCES);
306     }
307
308     @Test
309     public void testActivatePolicySession() throws Exception {
310         setUpKie(MY_SESS_NAME, 999L, true);
311         final PreparedStatement ps = mockDbConn(5);
312
313         feat.beforeActivate(null);
314
315         KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
316
317         verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
318         verify(kiestore, never()).newKieSession(any(), any(), any());
319
320         assertEquals(session, kiesess);
321
322         verify(ps).executeUpdate();
323
324         verify(kieenv, times(4)).set(anyString(), any());
325
326         verify(jpa).get(MY_SESS_NAME);
327         verify(jpa).replace(any());
328     }
329
330     @Test
331     public void testActivatePolicySession_NoPersistence() throws Exception {
332         setUpKie(MY_SESS_NAME, 999L, true);
333         final PreparedStatement ps = mockDbConn(5);
334
335         props.remove("persistence.type");
336
337         feat.beforeStart(null);
338
339         assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
340
341         verify(ps, never()).executeUpdate();
342         verify(kiestore, never()).loadKieSession(anyLong(), any(), any(), any());
343         verify(kiestore, never()).newKieSession(any(), any(), any());
344     }
345
346     /** Verifies that a new KIE session is created when there is no existing session entity. */
347     @Test
348     public void testActivatePolicySession_New() throws Exception {
349         setUpKie("noName", 999L, true);
350         mockDbConn(5);
351
352         KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
353
354         verify(kiestore, never()).loadKieSession(anyLong(), any(), any(), any());
355         verify(kiestore).newKieSession(any(), any(), any());
356
357         assertEquals(session, kiesess);
358
359         verify(kieenv, times(4)).set(anyString(), any());
360
361         verify(jpa).get(MY_SESS_NAME);
362         verify(jpa).replace(any());
363     }
364
365     /**
366      * Verifies that a new KIE session is created when there KIE fails to load an existing session.
367      */
368     @Test
369     public void testActivatePolicySession_LoadFailed() throws Exception {
370         setUpKie(MY_SESS_NAME, 999L, false);
371         mockDbConn(5);
372
373         KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
374
375         verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
376         verify(kiestore).newKieSession(any(), any(), any());
377
378         assertEquals(session, kiesess);
379
380         verify(kieenv, times(4)).set(anyString(), any());
381
382         verify(jpa).get(MY_SESS_NAME);
383
384         ArgumentCaptor<DroolsSession> drools = ArgumentCaptor.forClass(DroolsSession.class);
385         verify(jpa).replace(drools.capture());
386
387         assertEquals(MY_SESS_NAME, drools.getValue().getSessionName());
388         assertEquals(100L, drools.getValue().getSessionId());
389     }
390
391     @Test
392     public void testLoadDataSource() throws Exception {
393         setUpKie(MY_SESS_NAME, 999L, false);
394         mockDbConn(5);
395
396         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
397
398         assertEquals(1, emfCount);
399     }
400
401     @Test
402     public void testConfigureSysProps() throws Exception {
403         setUpKie(MY_SESS_NAME, 999L, false);
404         mockDbConn(5);
405
406         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
407
408         assertEquals("60", System.getProperty("com.arjuna.ats.arjuna.coordinator.defaultTimeout"));
409         assertEquals(JTA_OSDIR, System.getProperty("com.arjuna.ats.arjuna.objectstore.objectStoreDir"));
410         assertEquals(JTA_OSDIR, System.getProperty("ObjectStoreEnvironmentBean.objectStoreDir"));
411     }
412
413     @Test
414     public void testConfigureKieEnv() throws Exception {
415         setUpKie(MY_SESS_NAME, 999L, false);
416         mockDbConn(5);
417
418         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
419
420         verify(kieenv, times(4)).set(any(), any());
421
422         verify(kieenv).set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
423         verify(kieenv).set(EnvironmentName.TRANSACTION, usertrans);
424         verify(kieenv).set(EnvironmentName.TRANSACTION_MANAGER, transmgr);
425         verify(kieenv).set(EnvironmentName.TRANSACTION_SYNCHRONIZATION_REGISTRY, transreg);
426
427         verify(bds, times(1)).close();
428     }
429
430     @Test
431     public void testConfigureKieEnv_RtEx() throws Exception {
432         setUpKie(MY_SESS_NAME, 999L, false);
433         mockDbConn(5);
434
435         feat = new PersistenceFeatureMockDb() {
436             @Override
437             protected UserTransaction getUserTrans() {
438                 throw new IllegalArgumentException(EXPECTED);
439             }
440         };
441
442         feat.globalInit(null, SRC_TEST_RESOURCES);
443
444         try {
445             feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
446             fail(MISSING_EXCEPTION);
447
448         } catch (IllegalArgumentException ex) {
449             logger.trace(EXPECTED, ex);
450         }
451
452         verify(bds, times(2)).close();
453     }
454
455     @Test
456     public void testLoadKieSession() throws Exception {
457         setUpKie(MY_SESS_NAME, 999L, true);
458         mockDbConn(5);
459
460         KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
461
462         verify(kiestore).loadKieSession(999L, kiebase, kiecfg, kieenv);
463         verify(kiestore, never()).newKieSession(any(), any(), any());
464
465         assertEquals(session, kiesess);
466     }
467
468     /*
469      * Verifies that loadKieSession() returns null (thus causing newKieSession()
470      * to be called) when an Exception occurs.
471      */
472     @Test
473     public void testLoadKieSession_Ex() throws Exception {
474         setUpKie(MY_SESS_NAME, 999L, false);
475         mockDbConn(5);
476
477         when(kiestore.loadKieSession(anyLong(), any(), any(), any()))
478             .thenThrow(new IllegalArgumentException(EXPECTED));
479
480         KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
481
482         verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
483         verify(kiestore).newKieSession(any(), any(), any());
484
485         assertEquals(session, kiesess);
486     }
487
488     @Test
489     public void testNewKieSession() throws Exception {
490         setUpKie(MY_SESS_NAME, 999L, false);
491         mockDbConn(5);
492
493         KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
494
495         verify(kiestore).newKieSession(kiebase, null, kieenv);
496
497         assertEquals(session, kiesess);
498     }
499
500     @Test
501     public void testLoadDataSource_DiffSession() throws Exception {
502         setUpKie(MY_SESS_NAME, 999L, false);
503         mockDbConn(5);
504
505         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
506
507         ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
508                 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
509
510         verify(polcont).setAdjunct(any(), adjcap.capture());
511
512         when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
513
514         setUpKie("myname2", 999L, false);
515         mockDbConn(5);
516
517         // invoke it again
518         feat.activatePolicySession(polcont, "myname2", MY_KIE_BASE);
519
520         assertEquals(2, emfCount);
521     }
522
523     @Test
524     public void testSelectThreadModel_Persistent() throws Exception {
525         setUpKie(MY_SESS_NAME, 999L, true);
526
527         ThreadModel model = feat.selectThreadModel(polsess);
528         assertNotNull(model);
529         assertTrue(model instanceof PersistentThreadModel);
530     }
531
532     @Test
533     public void testSelectThreadModel_NotPersistent() throws Exception {
534         assertNull(feat.selectThreadModel(polsess));
535     }
536
537     @Test
538     public void testSelectThreadModel_Start__Run_Update_Stop() throws Exception {
539         setUpKie(MY_SESS_NAME, 999L, true);
540
541         ThreadModel model = feat.selectThreadModel(polsess);
542         assertNotNull(model);
543         assertTrue(model instanceof PersistentThreadModel);
544
545         when(polsess.getKieSession()).thenReturn(kiesess);
546
547         model.start();
548         new CountDownLatch(1).await(10, TimeUnit.MILLISECONDS);
549         model.updated();
550         model.stop();
551     }
552
553     @Test
554     public void testDisposeKieSession() throws Exception {
555         setUpKie(MY_SESS_NAME, 999L, false);
556         mockDbConn(5);
557
558         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
559
560         verify(emf, never()).close();
561
562         final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
563                 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
564
565         verify(polcont).setAdjunct(any(), adjcap.capture());
566
567         when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
568
569         feat.disposeKieSession(polsess);
570
571         // call twice to ensure it isn't re-closed
572         feat.disposeKieSession(polsess);
573
574         verify(emf, times(1)).close();
575     }
576
577     @Test
578     public void testDisposeKieSession_NoAdjunct() throws Exception {
579         feat.globalInit(null, SRC_TEST_RESOURCES);
580
581         assertThatCode(() -> feat.disposeKieSession(polsess)).doesNotThrowAnyException();
582     }
583
584     @Test
585     public void testDisposeKieSession_NoPersistence() throws Exception {
586         setUpKie(MY_SESS_NAME, 999L, false);
587         mockDbConn(5);
588
589         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
590
591         verify(emf, never()).close();
592
593         final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
594                 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
595
596         verify(polcont).setAdjunct(any(), adjcap.capture());
597
598         when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
599
600         // specify a session that was never loaded
601         when(polsess.getName()).thenReturn("anotherName");
602
603         feat.disposeKieSession(polsess);
604
605         verify(emf, never()).close();
606     }
607
608     @Test
609     public void testDestroyKieSession() throws Exception {
610         setUpKie(MY_SESS_NAME, 999L, false);
611         mockDbConn(5);
612
613         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
614
615         verify(emf, never()).close();
616
617         final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
618                 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
619
620         verify(polcont).setAdjunct(any(), adjcap.capture());
621
622         when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
623
624         feat.destroyKieSession(polsess);
625
626         // call twice to ensure it isn't re-closed
627         feat.destroyKieSession(polsess);
628
629         verify(emf, times(1)).close();
630     }
631
632     @Test
633     public void testDestroyKieSession_NoAdjunct() throws Exception {
634         feat.globalInit(null, SRC_TEST_RESOURCES);
635
636         assertThatCode(() -> feat.destroyKieSession(polsess)).doesNotThrowAnyException();
637     }
638
639     @Test
640     public void testDestroyKieSession_NoPersistence() throws Exception {
641         setUpKie(MY_SESS_NAME, 999L, false);
642         mockDbConn(5);
643
644         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
645
646         verify(emf, never()).close();
647
648         final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
649                 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
650
651         verify(polcont).setAdjunct(any(), adjcap.capture());
652
653         when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
654
655         // specify a session that was never loaded
656         when(polsess.getName()).thenReturn("anotherName");
657
658         feat.destroyKieSession(polsess);
659
660         verify(emf, never()).close();
661     }
662
663     @Test
664     public void testAfterStart() {
665         assertFalse(feat.afterStart(null));
666     }
667
668     @Test
669     public void testBeforeStart() {
670         assertFalse(feat.beforeStart(null));
671     }
672
673     @Test
674     public void testBeforeShutdown() {
675         assertFalse(feat.beforeShutdown(null));
676     }
677
678     @Test
679     public void testAfterShutdown() {
680         assertFalse(feat.afterShutdown(null));
681     }
682
683     @Test
684     public void testBeforeConfigure() {
685         assertFalse(feat.beforeConfigure(null, null));
686     }
687
688     @Test
689     public void testAfterConfigure() {
690         assertFalse(feat.afterConfigure(null));
691     }
692
693     @Test
694     public void testBeforeActivate() {
695         assertFalse(feat.beforeActivate(null));
696     }
697
698     @Test
699     public void testAfterActivate() {
700         assertFalse(feat.afterActivate(null));
701     }
702
703     @Test
704     public void testBeforeDeactivate() {
705         assertFalse(feat.beforeDeactivate(null));
706     }
707
708     @Test
709     public void testAfterDeactivate() {
710         assertFalse(feat.afterDeactivate(null));
711     }
712
713     @Test
714     public void testBeforeStop() {
715         assertFalse(feat.beforeStop(null));
716     }
717
718     @Test
719     public void testAfterStop() {
720         assertFalse(feat.afterStop(null));
721     }
722
723     @Test
724     public void testBeforeLock() {
725         assertFalse(feat.beforeLock(null));
726     }
727
728     @Test
729     public void testAfterLock() {
730         assertFalse(feat.afterLock(null));
731     }
732
733     @Test
734     public void testBeforeUnlock() {
735         assertFalse(feat.beforeUnlock(null));
736     }
737
738     @Test
739     public void testAfterUnlock() {
740         assertFalse(feat.afterUnlock(null));
741     }
742
743     @Test
744     public void testGetPersistenceTimeout_Valid() throws Exception {
745         setUpKie(MY_SESS_NAME, 999L, true);
746         final PreparedStatement statement = mockDbConn(5);
747
748         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
749
750         verify(statement).executeUpdate();
751     }
752
753     @Test
754     public void testGetPersistenceTimeout_Missing() throws Exception {
755
756         props.remove(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT);
757
758         setUpKie(MY_SESS_NAME, 999L, true);
759         final PreparedStatement statement = mockDbConn(0);
760
761         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
762
763         verify(statement, never()).executeUpdate();
764     }
765
766     @Test
767     public void testGetPersistenceTimeout_Invalid() throws Exception {
768         props.setProperty(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT, "abc");
769
770         setUpKie(MY_SESS_NAME, 999L, true);
771         final PreparedStatement s = mockDbConn(0);
772
773         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
774
775         verify(s, never()).executeUpdate();
776     }
777
778     @Test
779     public void testCleanUpSessionInfo() throws Exception {
780         setUpKie(MY_SESS_NAME, 999L, true);
781
782         // use a real DB so we can verify that the "delete" works correctly
783         feat = new PartialFeature();
784
785         makeSessionInfoTbl(20000);
786
787         // create mock entity manager for use by JPA connector
788         EntityManager em = mock(EntityManager.class);
789         when(emf.createEntityManager()).thenReturn(em);
790
791         feat.globalInit(null, SRC_TEST_RESOURCES);
792
793         feat.beforeStart(null);
794         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
795
796         assertEquals("[1, 4, 5]", getSessions().toString());
797     }
798
799     @Test
800     public void testCleanUpSessionInfo_WithBeforeStart() throws Exception {
801         setUpKie(MY_SESS_NAME, 999L, true);
802         final PreparedStatement statement = mockDbConn(0);
803
804         // reset
805         feat.beforeStart(null);
806
807         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
808         verify(statement, times(1)).executeUpdate();
809
810         // should not clean-up again
811         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
812         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
813         verify(statement, times(1)).executeUpdate();
814
815         // reset
816         feat.beforeStart(null);
817
818         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
819         verify(statement, times(2)).executeUpdate();
820
821         // should not clean-up again
822         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
823         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
824         verify(statement, times(2)).executeUpdate();
825     }
826
827     @Test
828     public void testCleanUpSessionInfo_WithBeforeActivate() throws Exception {
829         setUpKie(MY_SESS_NAME, 999L, true);
830         final PreparedStatement statement = mockDbConn(0);
831
832         // reset
833         feat.beforeActivate(null);
834
835         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
836         verify(statement, times(1)).executeUpdate();
837
838         // should not clean-up again
839         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
840         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
841         verify(statement, times(1)).executeUpdate();
842
843         // reset
844         feat.beforeActivate(null);
845
846         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
847         verify(statement, times(2)).executeUpdate();
848
849         // should not clean-up again
850         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
851         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
852         verify(statement, times(2)).executeUpdate();
853     }
854
855     @Test
856     public void testCleanUpSessionInfo_NoTimeout() throws Exception {
857
858         props.remove(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT);
859
860         setUpKie(MY_SESS_NAME, 999L, true);
861         final PreparedStatement statement = mockDbConn(0);
862
863         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
864
865         verify(statement, never()).executeUpdate();
866     }
867
868     @Test
869     public void testCleanUpSessionInfo_NoUrl() throws Exception {
870         props.remove(DroolsPersistenceProperties.DB_URL);
871
872         setUpKie(MY_SESS_NAME, 999L, true);
873         final PreparedStatement statement = mockDbConn(0);
874
875         try {
876             feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
877             fail(MISSING_EXCEPTION);
878         } catch (RuntimeException e) {
879             logger.trace(EXPECTED, e);
880         }
881
882         verify(statement, never()).executeUpdate();
883     }
884
885     @Test
886     public void testCleanUpSessionInfo_NoUser() throws Exception {
887         props.remove(DroolsPersistenceProperties.DB_USER);
888
889         setUpKie(MY_SESS_NAME, 999L, true);
890         final PreparedStatement statement = mockDbConn(0);
891
892         try {
893             feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
894             fail(MISSING_EXCEPTION);
895         } catch (RuntimeException e) {
896             logger.trace(EXPECTED, e);
897         }
898
899         verify(statement, never()).executeUpdate();
900     }
901
902     @Test
903     public void testCleanUpSessionInfo_NoPassword() throws Exception {
904         props.remove(DroolsPersistenceProperties.DB_PWD);
905
906         setUpKie(MY_SESS_NAME, 999L, true);
907         final PreparedStatement statement = mockDbConn(0);
908
909         try {
910             feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
911             fail(MISSING_EXCEPTION);
912         } catch (RuntimeException e) {
913             logger.trace(EXPECTED, e);
914         }
915
916         verify(statement, never()).executeUpdate();
917     }
918
919     @Test
920     public void testCleanUpSessionInfo_SqlEx() throws Exception {
921         setUpKie(MY_SESS_NAME, 999L, true);
922         final PreparedStatement statement = mockDbConn(-1);
923
924         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
925
926         verify(statement).executeUpdate();
927     }
928
929     @Test
930     public void testGetDroolsSessionConnector() throws Exception {
931         setUpKie(MY_SESS_NAME, 999L, true);
932         mockDbConn(5);
933
934         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
935
936         assertEquals(1, jpaCount);
937     }
938
939     @Test
940     public void testReplaceSession() throws Exception {
941         setUpKie(MY_SESS_NAME, 999L, true);
942         mockDbConn(5);
943
944         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
945
946         final ArgumentCaptor<DroolsSession> sesscap = ArgumentCaptor.forClass(DroolsSession.class);
947
948         verify(jpa).replace(sesscap.capture());
949
950         assertEquals(MY_SESS_NAME, sesscap.getValue().getSessionName());
951         assertEquals(999L, sesscap.getValue().getSessionId());
952     }
953
954     @Test
955     public void testIsPersistenceEnabled_Auto() throws Exception {
956         setUpKie(MY_SESS_NAME, 999L, true);
957         mockDbConn(5);
958
959         props.setProperty("persistence.type", "auto");
960
961         assertNotNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
962     }
963
964     @Test
965     public void testIsPersistenceEnabled_Native() throws Exception {
966         setUpKie(MY_SESS_NAME, 999L, true);
967         mockDbConn(5);
968
969         props.setProperty("persistence.type", "native");
970
971         assertNotNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
972     }
973
974     @Test
975     public void testIsPersistenceEnabled_None() throws Exception {
976         setUpKie(MY_SESS_NAME, 999L, true);
977         mockDbConn(5);
978
979         props.remove("persistence.type");
980
981         assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
982     }
983
984     @Test
985     public void testGetProperties_Ex() throws Exception {
986         setUpKie(MY_SESS_NAME, 999L, true);
987         mockDbConn(5);
988
989         feat = new PersistenceFeatureMockDb() {
990             @Override
991             protected PolicyController getPolicyController(PolicyContainer container) {
992                 throw new IllegalArgumentException(EXPECTED);
993             }
994         };
995
996         assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
997     }
998
999     @Test
1000     public void testGetProperty_Specific() throws Exception {
1001         setUpKie(MY_SESS_NAME, 999L, true);
1002         mockDbConn(5);
1003
1004         props.remove("persistence.type");
1005         props.setProperty("persistence.myname.type", "auto");
1006
1007         assertNotNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1008     }
1009
1010     @Test
1011     public void testGetProperty_Specific_None() throws Exception {
1012         setUpKie(MY_SESS_NAME, 999L, true);
1013         mockDbConn(5);
1014
1015         props.remove("persistence.type");
1016         props.setProperty("persistence.xxx.type", "auto");
1017
1018         assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1019     }
1020
1021     @Test
1022     public void testGetProperty_Both_SpecificOn() throws Exception {
1023         setUpKie(MY_SESS_NAME, 999L, true);
1024         mockDbConn(5);
1025
1026         props.setProperty("persistence.type", "other");
1027         props.setProperty("persistence.myname.type", "auto");
1028
1029         assertNotNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1030     }
1031
1032     @Test
1033     public void testGetProperty_Both_SpecificDisabledOff() throws Exception {
1034         setUpKie(MY_SESS_NAME, 999L, true);
1035         mockDbConn(5);
1036
1037         props.setProperty("persistence.type", "auto");
1038         props.setProperty("persistence.myname.type", "other");
1039
1040         assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1041     }
1042
1043     @Test
1044     public void testGetProperty_None() throws Exception {
1045         setUpKie(MY_SESS_NAME, 999L, true);
1046         mockDbConn(5);
1047
1048         props.remove("persistence.type");
1049
1050         assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1051     }
1052
1053     @Test
1054     public void testPersistenceFeatureException() {
1055         SecurityException secex = new SecurityException(EXPECTED);
1056         PersistenceFeatureException ex = new PersistenceFeatureException(secex);
1057
1058         assertEquals(secex, ex.getCause());
1059     }
1060
1061     @Test
1062     public void testDsEmf_RtEx() throws Exception {
1063         setUpKie(MY_SESS_NAME, 999L, false);
1064         mockDbConn(5);
1065
1066         feat = new PersistenceFeatureMockDb() {
1067             @Override
1068             protected EntityManagerFactory makeEntMgrFact(Map<String, Object> props) {
1069                 throw new IllegalArgumentException(EXPECTED);
1070             }
1071         };
1072
1073         feat.globalInit(null, SRC_TEST_RESOURCES);
1074
1075         try {
1076             feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
1077             fail(MISSING_EXCEPTION);
1078
1079         } catch (IllegalArgumentException ex) {
1080             logger.trace(EXPECTED, ex);
1081         }
1082
1083         verify(bds, times(2)).close();
1084     }
1085
1086     @Test
1087     public void testDsEmf_Close_RtEx() throws Exception {
1088         setUpKie(MY_SESS_NAME, 999L, false);
1089         mockDbConn(5);
1090
1091         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
1092
1093         ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
1094                 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
1095
1096         verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
1097
1098         // return adjunct on next call
1099         when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
1100
1101         IllegalArgumentException exception = new IllegalArgumentException(EXPECTED);
1102         doThrow(exception).when(emf).close();
1103         assertThatCode(() -> feat.destroyKieSession(polsess)).isEqualTo(exception);
1104
1105         verify(bds, times(2)).close();
1106     }
1107
1108     @Test
1109     public void testDsEmf_CloseDataSource_RtEx() throws Exception {
1110         setUpKie(MY_SESS_NAME, 999L, false);
1111         mockDbConn(5);
1112
1113         feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
1114
1115         ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
1116                 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
1117
1118         verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
1119
1120         // return adjunct on next call
1121         when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
1122
1123         SQLException cause = new SQLException(EXPECTED);
1124         doThrow(cause).when(bds).close();
1125         assertThatCode(() -> feat.destroyKieSession(polsess)).isInstanceOf(PersistenceFeatureException.class)
1126                         .hasCause(cause);
1127     }
1128
1129     /**
1130      * Gets an ordered list of ids of the current SessionInfo records.
1131      *
1132      * @return ordered list of SessInfo IDs
1133      * @throws SQLException sql exception
1134      * @throws IOException io exception
1135      */
1136     private List<Integer> getSessions() throws SQLException, IOException {
1137         attachDb();
1138
1139         ArrayList<Integer> lst = new ArrayList<>(5);
1140
1141         try (PreparedStatement stmt = conn.prepareStatement("SELECT id from sessioninfo order by id");
1142                 ResultSet rs = stmt.executeQuery()) {
1143
1144             while (rs.next()) {
1145                 lst.add(rs.getInt(1));
1146             }
1147         }
1148
1149         return lst;
1150     }
1151
1152     /**
1153      * Sets up for doing invoking the newKieSession() method.
1154      *
1155      * @param sessnm name to which JPA should respond with a session
1156      * @param sessid session id to be returned by the session
1157      * @param loadOk {@code true} if loadKieSession() should return a value, {@code false} to return
1158      *     null
1159      * @throws Exception exception
1160      */
1161     private void setUpKie(String sessnm, long sessid, boolean loadOk) throws Exception {
1162         props.setProperty("persistence.type", "auto");
1163
1164         when(polctlr.getProperties()).thenReturn(props);
1165
1166         when(jpa.get(sessnm)).thenReturn(sess);
1167
1168         when(sess.getSessionId()).thenReturn(sessid);
1169
1170         when(polsess.getContainer()).thenReturn(polcont);
1171         when(polsess.getName()).thenReturn(sessnm);
1172
1173         if (loadOk) {
1174             when(kiesess.getIdentifier()).thenReturn(sessid);
1175             when(kiestore.loadKieSession(anyLong(), any(), any(), any())).thenReturn(kiesess);
1176
1177         } else {
1178             // use an alternate id for the new session
1179             when(kiesess.getIdentifier()).thenReturn(100L);
1180             when(kiestore.loadKieSession(anyLong(), any(), any(), any())).thenReturn(null);
1181         }
1182
1183         when(kiestore.newKieSession(any(), any(), any())).thenReturn(kiesess);
1184
1185         feat = new PersistenceFeatureKie();
1186         feat.globalInit(null, SRC_TEST_RESOURCES);
1187     }
1188
1189     /**
1190      * Creates the SessionInfo DB table and populates it with some data.
1191      *
1192      * @param expMs number of milli-seconds for expired sessioninfo records
1193      * @throws SQLException exception
1194      * @throws IOException exception
1195      */
1196     private void makeSessionInfoTbl(int expMs) throws SQLException, IOException {
1197
1198         attachDb();
1199
1200         try (PreparedStatement stmt =
1201                 conn.prepareStatement("CREATE TABLE sessioninfo(id int, lastmodificationdate timestamp)")) {
1202
1203             stmt.executeUpdate();
1204         }
1205
1206         try (PreparedStatement stmt =
1207                 conn.prepareStatement("INSERT into sessioninfo(id, lastmodificationdate) values(?, ?)")) {
1208
1209             Timestamp ts;
1210
1211             // current data
1212             ts = new Timestamp(System.currentTimeMillis());
1213             stmt.setTimestamp(2, ts);
1214
1215             stmt.setInt(1, 1);
1216             stmt.executeUpdate();
1217
1218             stmt.setInt(1, 4);
1219             stmt.executeUpdate();
1220
1221             stmt.setInt(1, 5);
1222             stmt.executeUpdate();
1223
1224             // expired data
1225             ts = new Timestamp(System.currentTimeMillis() - expMs);
1226             stmt.setTimestamp(2, ts);
1227
1228             stmt.setInt(1, 2);
1229             stmt.executeUpdate();
1230
1231             stmt.setInt(1, 3);
1232             stmt.executeUpdate();
1233         }
1234     }
1235
1236     /**
1237      * Attaches {@link #conn} to the DB, if it isn't already attached.
1238      *
1239      * @throws SQLException sql exception
1240      * @throws IOException if the property file cannot be read
1241      */
1242     private void attachDb() throws SQLException, IOException {
1243         if (conn == null) {
1244             Properties props = loadDbProps();
1245
1246             conn =
1247                     DriverManager.getConnection(
1248                             props.getProperty(DroolsPersistenceProperties.DB_URL),
1249                             props.getProperty(DroolsPersistenceProperties.DB_USER),
1250                             props.getProperty(DroolsPersistenceProperties.DB_PWD));
1251             conn.setAutoCommit(true);
1252         }
1253     }
1254
1255     /**
1256      * Loads the DB properties from the file, <i>feature-session-persistence.properties</i>.
1257      *
1258      * @return the properties that were loaded
1259      * @throws IOException if the property file cannot be read
1260      * @throws FileNotFoundException if the property file does not exist
1261      */
1262     private Properties loadDbProps() throws IOException, FileNotFoundException {
1263
1264         Properties props = new Properties();
1265
1266         try (FileReader rdr =
1267                 new FileReader("src/test/resources/feature-session-persistence.properties")) {
1268             props.load(rdr);
1269         }
1270
1271         return props;
1272     }
1273
1274     /**
1275      * Create a mock DB connection and statement.
1276      *
1277      * @param retval value to be returned when the statement is executed, or negative to throw an
1278      *     exception
1279      * @return the statement that will be returned by the connection
1280      * @throws SQLException sql exception
1281      */
1282     private PreparedStatement mockDbConn(int retval) throws SQLException {
1283         Connection connection = mock(Connection.class);
1284         PreparedStatement statement = mock(PreparedStatement.class);
1285
1286         when(bds.getConnection()).thenReturn(connection);
1287         when(connection.prepareStatement(anyString())).thenReturn(statement);
1288
1289         if (retval < 0) {
1290             // should throw an exception
1291             when(statement.executeUpdate()).thenThrow(new SQLException(EXPECTED));
1292
1293         } else {
1294             // should return the value
1295             when(statement.executeUpdate()).thenReturn(retval);
1296         }
1297
1298         feat = new PersistenceFeatureMockDb();
1299         feat.globalInit(null, SRC_TEST_RESOURCES);
1300
1301         return statement;
1302     }
1303
1304     /**
1305      * Feature with a mock DB.
1306      */
1307     private class PersistenceFeatureMockDb extends PersistenceFeatureKie {
1308
1309         @Override
1310         protected BasicDataSource makeDataSource(Properties dsProps) {
1311             return bds;
1312         }
1313     }
1314
1315     /**
1316      * Feature supporting newKieSession.
1317      */
1318     private class PersistenceFeatureKie extends PersistenceFeatureImpl {
1319
1320         @Override
1321         protected EntityManagerFactory makeEntMgrFact(Map<String, Object> props) {
1322             ++emfCount;
1323             return emf;
1324         }
1325
1326         @Override
1327         protected DroolsSessionConnector makeJpaConnector(EntityManagerFactory emf) {
1328             ++jpaCount;
1329             return jpa;
1330         }
1331     }
1332
1333     /**
1334      * Feature with overrides.
1335      */
1336     private class PersistenceFeatureImpl extends PartialFeature {
1337
1338         @Override
1339         protected Properties loadProperties(String filenm) throws IOException {
1340             propName = filenm;
1341             return props;
1342         }
1343
1344         @Override
1345         protected BasicDataSource makeDataSource(Properties dsProps) {
1346             return null;
1347         }
1348
1349         @Override
1350         protected DroolsSessionConnector makeJpaConnector(EntityManagerFactory emf) {
1351             ++jpaCount;
1352             return null;
1353         }
1354     }
1355
1356     /**
1357      * Feature with <i>some</i> overrides.
1358      */
1359     private class PartialFeature extends PersistenceFeature {
1360
1361         @Override
1362         protected TransactionManager getTransMgr() {
1363             return transmgr;
1364         }
1365
1366         @Override
1367         protected UserTransaction getUserTrans() {
1368             return usertrans;
1369         }
1370
1371         @Override
1372         protected TransactionSynchronizationRegistry getTransSyncReg() {
1373             return transreg;
1374         }
1375
1376         @Override
1377         protected KieServices getKieServices() {
1378             return kiesvc;
1379         }
1380
1381         @Override
1382         protected EntityManagerFactory makeEntMgrFact(Map<String, Object> props) {
1383             ++emfCount;
1384             return emf;
1385         }
1386
1387         @Override
1388         protected PolicyController getPolicyController(PolicyContainer container) {
1389             return polctlr;
1390         }
1391     }
1392 }