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