use shutdown to clear handle leak 17/104017/4
authorPamela Dragosh <pdragosh@research.att.com>
Thu, 19 Mar 2020 23:58:13 +0000 (19:58 -0400)
committerPamela Dragosh <pdragosh@research.att.com>
Fri, 20 Mar 2020 14:01:13 +0000 (10:01 -0400)
The XACML github was released with a new method to allow
context factories and PIP engines to release any handles
before releasing the PDP engine. This review includes
that artifact and adds tests to support it.

In addition, added more tests to get code coverage over
90% for both PIPs in ONAP.

Some cleanup in the Matchable types based on last review.

Issue-ID: POLICY-2242
Change-Id: I312f06380ff4d2e16bcfd25b6d1f36ce5dd030e6
Signed-off-by: Pamela Dragosh <pdragosh@research.att.com>
applications/common/pom.xml
applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/matchable/MatchablePolicyType.java
applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/matchable/MatchablePropertyTypeList.java
applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/operationshistory/CountRecentOperationsPip.java
applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/operationshistory/GetOperationOutcomePip.java
applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdOnapPip.java
applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdXacmlApplicationServiceProvider.java
applications/common/src/test/java/org/onap/policy/pdp/xacml/application/common/operationshistory/CountRecentOperationsPipTest.java
applications/common/src/test/java/org/onap/policy/pdp/xacml/application/common/operationshistory/GetOperationOutcomePipTest.java
applications/common/src/test/java/org/onap/policy/pdp/xacml/application/common/std/StdOnapPipTest.java

index 5a359e6..7d559cc 100644 (file)
@@ -76,7 +76,7 @@
         <dependency>
             <groupId>com.att.research.xacml</groupId>
             <artifactId>xacml-pdp</artifactId>
-            <version>2.1.0</version>
+            <version>2.2.0</version>
         </dependency>
     </dependencies>
 </project>
index 3bbc6ea..cf9d7a9 100644 (file)
@@ -48,6 +48,7 @@ public class MatchablePolicyType {
     public static final String TOSCA_TYPE_LIST = "list";
     public static final String TOSCA_TYPE_MAP = "map";
 
+    //@formatter:off
     private static final Map<String, Function<ToscaProperty, MatchablePropertyTypeBase<?>>>
         mapPrimitivesProperty = Map.of(
             TOSCA_PRIMITIVE_STRING, MatchablePropertyTypeString::new,
@@ -65,6 +66,7 @@ public class MatchablePolicyType {
             TOSCA_PRIMITIVE_BOOLEAN, MatchablePropertyTypeBoolean::new,
             TOSCA_PRIMITIVE_TIMESTAMP, MatchablePropertyTypeTimestamp::new
             );
+    //@formatter:on
 
     ToscaPolicyIdentifier policyId;
     Map<String, MatchableProperty> matchables = new HashMap<>();
@@ -170,7 +172,7 @@ public class MatchablePolicyType {
         Function<ToscaEntrySchema, MatchablePropertyTypeBase<?>> function =
                 mapPrimitivesSchema.get(toscaSchema.getType());
         if (function != null) {
-            return new MatchableProperty(property, function.apply(toscaSchema)); // compilation err wants ToscaProperty
+            return new MatchableProperty(property, function.apply(toscaSchema));
         }
         throw new IllegalArgumentException("Not a primitive " + toscaSchema.getType());
     }
index 55fea54..7b19ad4 100644 (file)
@@ -23,7 +23,6 @@
 package org.onap.policy.pdp.xacml.application.common.matchable;
 
 import com.att.research.xacml.api.Identifier;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
@@ -50,7 +49,7 @@ public class MatchablePropertyTypeList extends MatchablePropertyTypeBase<List<Ma
     @SuppressWarnings("unchecked")
     @Override
     public List<MatchablePropertyType<?>> validate(Object value) throws ToscaPolicyConversionException {
-        if (value instanceof Collection) {
+        if (value instanceof List) {
             return (List<MatchablePropertyType<?>>) value;
         }
         return Collections.emptyList();
index 4bf8777..f2d7980 100644 (file)
@@ -62,6 +62,9 @@ public class CountRecentOperationsPip extends StdOnapPip {
      */
     @Override
     public PIPResponse getAttributes(PIPRequest pipRequest, PIPFinder pipFinder) throws PIPException {
+        if (this.shutdown) {
+            throw new PIPException("Engine is shutdown");
+        }
         logger.debug("getAttributes requesting attribute {} of type {} for issuer {}",
                 pipRequest.getAttributeId(), pipRequest.getDataTypeId(), pipRequest.getIssuer());
         //
index 0f970f7..b269e25 100644 (file)
@@ -58,6 +58,9 @@ public class GetOperationOutcomePip extends StdOnapPip {
      */
     @Override
     public PIPResponse getAttributes(PIPRequest pipRequest, PIPFinder pipFinder) throws PIPException {
+        if (this.shutdown) {
+            throw new PIPException("Engine is shutdown");
+        }
         logger.debug("getAttributes requesting attribute {} of type {} for issuer {}",
                 pipRequest.getAttributeId(), pipRequest.getDataTypeId(), pipRequest.getIssuer());
         //
index ca07f22..5c99932 100644 (file)
@@ -70,6 +70,7 @@ public abstract class StdOnapPip extends StdConfigurableEngine {
     protected Properties properties;
     protected EntityManager em;
     protected String issuer;
+    protected boolean shutdown = false;
 
     public StdOnapPip() {
         super();
@@ -81,7 +82,14 @@ public abstract class StdOnapPip extends StdConfigurableEngine {
     }
 
     @Override
-    public void configure(String id, Properties properties) throws PIPException {
+    public synchronized void configure(String id, Properties properties) throws PIPException {
+        //
+        // This most likely will never get called since configure is called
+        // upon startup.
+        //
+        if (this.shutdown) {
+            throw new PIPException("Engine is shutdown.");
+        }
         super.configure(id, properties);
         logger.info("Configuring historyDb PIP {}", properties);
         this.properties = properties;
@@ -114,6 +122,15 @@ public abstract class StdOnapPip extends StdConfigurableEngine {
         }
     }
 
+    @Override
+    public synchronized void shutdown() {
+        if (this.em != null) {
+            this.em.close();
+            this.em = null;
+        }
+        this.shutdown = true;
+    }
+
     protected String getAttribute(PIPFinder pipFinder, PIPRequest pipRequest) {
         //
         // Get the actor value
index 9a8b63f..ba562b8 100644 (file)
@@ -283,6 +283,13 @@ public abstract class StdXacmlApplicationServiceProvider implements XacmlApplica
             PDPEngineFactory factory = getPdpEngineFactory();
             PDPEngine engine = factory.newEngine(properties);
             if (engine != null) {
+                //
+                // If there is a previous engine have it shutdown.
+                //
+                this.destroyEngine();
+                //
+                // Save it off
+                //
                 this.pdpEngine = engine;
             }
         } catch (FactoryException e) {
@@ -290,6 +297,18 @@ public abstract class StdXacmlApplicationServiceProvider implements XacmlApplica
         }
     }
 
+    protected synchronized void destroyEngine() {
+        if (this.pdpEngine == null) {
+            return;
+        }
+        try {
+            this.pdpEngine.shutdown();
+        } catch (Exception e) {
+            LOGGER.warn("Exception thrown when destroying XACML PDP engine.", e);
+        }
+        this.pdpEngine = null;
+    }
+
     /**
      * Make a decision call.
      *
index 9a0eb6d..29eb2a0 100644 (file)
@@ -19,6 +19,7 @@
 package org.onap.policy.pdp.xacml.application.common.operationshistory;
 
 import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
@@ -197,6 +198,13 @@ public class CountRecentOperationsPipTest {
         assertEquals(StdPIPResponse.PIP_RESPONSE_EMPTY, pipEngine.getAttributes(pipRequest, pipFinder));
     }
 
+    @Test
+    public void testShutdown() {
+        pipEngine.shutdown();
+        assertThatExceptionOfType(PIPException.class).isThrownBy(() -> pipEngine.getAttributes(pipRequest, pipFinder))
+            .withMessageContaining("Engine is shutdown");
+    }
+
     @Test
     public void testGetCountFromDb() throws Exception {
         //
index f4ed1a3..e0dc7cd 100644 (file)
 
 package org.onap.policy.pdp.xacml.application.common.operationshistory;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.when;
 
+import com.att.research.xacml.api.Status;
 import com.att.research.xacml.api.pip.PIPException;
 import com.att.research.xacml.api.pip.PIPFinder;
 import com.att.research.xacml.api.pip.PIPRequest;
+import com.att.research.xacml.api.pip.PIPResponse;
 import com.att.research.xacml.std.pip.StdPIPResponse;
 import java.io.FileInputStream;
 import java.lang.reflect.Method;
@@ -40,6 +47,7 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -58,6 +66,12 @@ public class GetOperationOutcomePipTest {
     @Mock
     private PIPFinder pipFinder;
 
+    @Mock
+    private PIPResponse resp1;
+
+    @Mock
+    private Status okStatus;
+
     /**
      * Create an instance of our engine and also the persistence
      * factory.
@@ -124,7 +138,6 @@ public class GetOperationOutcomePipTest {
         pipEngine.configure("issuer", properties);
         LOGGER.info("PIP configured now creating our entity manager");
         LOGGER.info("properties {}", properties);
-
     }
 
     @Test
@@ -152,6 +165,24 @@ public class GetOperationOutcomePipTest {
         assertEquals(StdPIPResponse.PIP_RESPONSE_EMPTY, pipEngine.getAttributes(pipRequest, pipFinder));
     }
 
+    @Test
+    public void testGetAttributes() throws Exception {
+        //
+        //
+        //
+        when(pipRequest.getIssuer()).thenReturn(ToscaDictionary.GUARD_ISSUER_PREFIX + "clname:clfoo");
+        when(pipFinder.getMatchingAttributes(any(), eq(pipEngine))).thenReturn(resp1);
+        when(resp1.getStatus()).thenReturn(okStatus);
+        when(okStatus.isOk()).thenReturn(true);
+
+        assertNotEquals(StdPIPResponse.PIP_RESPONSE_EMPTY, pipEngine.getAttributes(pipRequest, pipFinder));
+
+        pipEngine.shutdown();
+
+        assertThatExceptionOfType(PIPException.class).isThrownBy(() -> pipEngine.getAttributes(pipRequest, pipFinder))
+            .withMessageContaining("Engine is shutdown");
+    }
+
     @Test
     public void testGetOutcomeFromDb() throws Exception {
         //
@@ -162,13 +193,18 @@ public class GetOperationOutcomePipTest {
                                                                        String.class);
         method.setAccessible(true);
         //
+        // Test pipEngine
+        //
+        String outcome = (String) method.invoke(pipEngine, "testcl1", "testtarget1");
+        assertThat(outcome).isNull();
+        //
         // Insert entry
         //
         insertEntry("testcl1", "testtarget1", "1");
         //
         // Test pipEngine
         //
-        String outcome = (String) method.invoke(pipEngine, "testcl1", "testtarget1");
+        outcome = (String) method.invoke(pipEngine, "testcl1", "testtarget1");
         //
         // outcome should be "1"
         //
@@ -190,6 +226,13 @@ public class GetOperationOutcomePipTest {
 
         outcome = (String) method.invoke(pipEngine, "testcl1", "testtarget2");
         assertEquals("4", outcome);
+
+        //
+        // Shut it down
+        //
+        pipEngine.shutdown();
+
+        assertThat(method.invoke(pipEngine, "testcl1", "testtarget2")).isNull();
     }
 
     private void insertEntry(String cl, String target, String outcome) {
index 1a9901b..a0f8573 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,6 +20,8 @@
 
 package org.onap.policy.pdp.xacml.application.common.std;
 
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
@@ -299,6 +301,13 @@ public class StdOnapPipTest {
         assertEquals(0, resp.getAttributes().size());
     }
 
+    @Test
+    public void testShutdown() {
+        assertThatCode(() -> pip.shutdown()).doesNotThrowAnyException();
+        assertThatExceptionOfType(PIPException.class).isThrownBy(() -> pip.configure("foo", new Properties()))
+            .withMessageContaining("Engine is shutdown");
+    }
+
     private class MyPip extends StdOnapPip {
 
         @Override