Merge "Remove drools PDP dependency"
diff --git a/models-pdp/src/main/java/org/onap/policy/models/pdp/concepts/PdpMessage.java b/models-pdp/src/main/java/org/onap/policy/models/pdp/concepts/PdpMessage.java
index a48724e..5d0359c 100644
--- a/models-pdp/src/main/java/org/onap/policy/models/pdp/concepts/PdpMessage.java
+++ b/models-pdp/src/main/java/org/onap/policy/models/pdp/concepts/PdpMessage.java
@@ -24,6 +24,7 @@
 import java.util.UUID;
 import lombok.AccessLevel;
 import lombok.Getter;
+import lombok.NonNull;
 import lombok.Setter;
 import lombok.ToString;
 import org.onap.policy.models.pdp.enums.PdpMessageType;
@@ -89,4 +90,43 @@
         this.pdpGroup = source.pdpGroup;
         this.pdpSubgroup = source.pdpSubgroup;
     }
+
+    /**
+     * Determines if this message applies to this PDP.
+     *
+     * @param pdpName name of this PDP
+     * @param group group to which this PDP has been assigned, or {@code null} if the PDP
+     *        has not been assigned to a group yet
+     * @param subgroup group to which this PDP has been assigned, or {@code null} if the
+     *        PDP has not been assigned to a subgroup yet
+     * @return {@code true} if this message applies to this PDP, {@code false} otherwise
+     */
+    public boolean appliesTo(@NonNull String pdpName, String group, String subgroup) {
+        if (pdpName.equals(name)) {
+            return true;
+        }
+
+        if (name != null) {
+            // message included a PDP name, but it does not match
+            return false;
+        }
+
+        // message does not provide a PDP name - must be a broadcast
+
+        if (group == null || subgroup == null) {
+            // this PDP has no assignment yet, thus should ignore broadcast messages
+            return false;
+        }
+
+        if (!group.equals(pdpGroup)) {
+            return false;
+        }
+
+        if (pdpSubgroup == null) {
+            // message was broadcast to entire group
+            return true;
+        }
+
+        return subgroup.equals(pdpSubgroup);
+    }
 }
diff --git a/models-pdp/src/main/java/org/onap/policy/models/pdp/concepts/PdpUpdate.java b/models-pdp/src/main/java/org/onap/policy/models/pdp/concepts/PdpUpdate.java
index a28bd76..5d0e225 100644
--- a/models-pdp/src/main/java/org/onap/policy/models/pdp/concepts/PdpUpdate.java
+++ b/models-pdp/src/main/java/org/onap/policy/models/pdp/concepts/PdpUpdate.java
@@ -30,7 +30,9 @@
 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
 
 /**
- * Class to represent the PDP_UPDATE message that PAP will send to a PDP.
+ * Class to represent the PDP_UPDATE message that PAP will send to a PDP. When a PDP
+ * receives this message, it should save the group and subgroup and pass them to
+ * {@link #appliesTo(String, String, String)} of subsequent messages that it receives.
  *
  * @author Ram Krishna Verma (ram.krishna.verma@est.tech)
  */
@@ -45,6 +47,13 @@
     private String description;
 
     private Long pdpHeartbeatIntervalMs;
+
+    /**
+     * Policies that the PDP should deploy. This is a complete list, so PDPs should be
+     * prepared to deploy new policies listed and undeploy policies that are no longer
+     * listed. Note: this list may be empty, as a PDP may remain attached to a subgroup
+     * even if all of the policies are removed from the subgroup.
+     */
     private List<ToscaPolicy> policies;
 
     /**
diff --git a/models-pdp/src/test/java/org/onap/policy/models/pdp/concepts/TestPdpMessage.java b/models-pdp/src/test/java/org/onap/policy/models/pdp/concepts/TestPdpMessage.java
index 515c483..0d3f591 100644
--- a/models-pdp/src/test/java/org/onap/policy/models/pdp/concepts/TestPdpMessage.java
+++ b/models-pdp/src/test/java/org/onap/policy/models/pdp/concepts/TestPdpMessage.java
@@ -23,35 +23,138 @@
 
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import org.junit.Test;
 import org.onap.policy.models.pdp.enums.PdpMessageType;
 
 /**
- * Test the copy constructor, as {@link TestModels} tests the other methods.
+ * Tests methods not already tested by {@link TestModels}.
  */
 public class TestPdpMessage {
+    private static final String PDP_NAME = "pdpA";
+    private static final String PDP_GROUP = "groupA";
+    private static final String PDP_SUBGROUP = "subgroupA";
+    private static final String DIFFERENT = "differentValue";
+
+    private PdpMessage message;
 
     @Test
     public void testCopyConstructor() {
         assertThatThrownBy(() -> new PdpMessage((PdpMessage) null)).isInstanceOf(NullPointerException.class);
 
-        PdpMessage orig = new PdpMessage(PdpMessageType.PDP_STATE_CHANGE);
-
         // verify with null values
-        PdpMessage newmsg = new PdpMessage(orig);
-        newmsg.setRequestId(orig.getRequestId());
-        newmsg.setTimestampMs(orig.getTimestampMs());
-        assertEquals(orig.toString(), newmsg.toString());
+        message = new PdpMessage(PdpMessageType.PDP_STATE_CHANGE);
+        PdpMessage newmsg = new PdpMessage(message);
+        newmsg.setRequestId(message.getRequestId());
+        newmsg.setTimestampMs(message.getTimestampMs());
+        assertEquals(message.toString(), newmsg.toString());
 
         // verify with all values
-        orig.setName("my-name");
-        orig.setPdpGroup("my-group");
-        orig.setPdpSubgroup("my-subgroup");
+        message = makeMessage(PDP_NAME, PDP_GROUP, PDP_SUBGROUP);
+        newmsg = new PdpMessage(message);
+        newmsg.setRequestId(message.getRequestId());
+        newmsg.setTimestampMs(message.getTimestampMs());
+        assertEquals(message.toString(), newmsg.toString());
+    }
 
-        newmsg = new PdpMessage(orig);
-        newmsg.setRequestId(orig.getRequestId());
-        newmsg.setTimestampMs(orig.getTimestampMs());
-        assertEquals(orig.toString(), newmsg.toString());
+    @Test
+    public void testAppliesTo_NameCombos() {
+        /*
+         * Test cases where the name matches.
+         */
+        for (String msgGroup : new String[] {null, PDP_GROUP, DIFFERENT}) {
+            for (String msgSubgroup : new String[] {null, PDP_SUBGROUP, DIFFERENT}) {
+                message = makeMessage(PDP_NAME, msgGroup, msgSubgroup);
+
+                for (String pdpGroup : new String[] {null, PDP_GROUP, DIFFERENT}) {
+                    for (String pdpSubgroup : new String[] {null, PDP_SUBGROUP, DIFFERENT}) {
+                        assertTrue("name msg " + message + " pdp group " + pdpGroup + "/" + pdpSubgroup,
+                                        message.appliesTo(PDP_NAME, pdpGroup, pdpSubgroup));
+                    }
+                }
+            }
+        }
+
+        /*
+         * Test cases where the name does not match.
+         */
+        for (String msgGroup : new String[] {null, PDP_GROUP, DIFFERENT}) {
+            for (String msgSubgroup : new String[] {null, PDP_SUBGROUP, DIFFERENT}) {
+                message = makeMessage(PDP_NAME, msgGroup, msgSubgroup);
+
+                for (String pdpGroup : new String[] {null, PDP_GROUP, DIFFERENT}) {
+                    for (String pdpSubgroup : new String[] {null, PDP_SUBGROUP, DIFFERENT}) {
+                        assertFalse("name msg " + message + " pdp group " + pdpGroup + "/" + pdpSubgroup,
+                                        message.appliesTo(DIFFERENT, pdpGroup, pdpSubgroup));
+                    }
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testAppliesTo_BroadcastGroup() {
+        /*
+         * Test cases where the group matches.
+         */
+        for (String msgSubgroup : new String[] {null, PDP_SUBGROUP}) {
+            message = makeMessage(null, PDP_GROUP, msgSubgroup);
+
+            assertTrue("group msg " + message, message.appliesTo(PDP_NAME, PDP_GROUP, PDP_SUBGROUP));
+        }
+
+        /*
+         * Test cases where the group does not match.
+         */
+        for (String msgGroup : new String[] {null, PDP_GROUP}) {
+            for (String msgSubgroup : new String[] {null, PDP_SUBGROUP}) {
+                message = makeMessage(null, msgGroup, msgSubgroup);
+
+                for (String pdpGroup : new String[] {null, DIFFERENT}) {
+                    assertFalse("group msg " + message + " pdp group " + pdpGroup,
+                                    message.appliesTo(PDP_NAME, pdpGroup, PDP_SUBGROUP));
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testAppliesTo_BroadcastSubGroup() {
+        /*
+         * Test cases where the subgroup matches.
+         */
+        message = makeMessage(null, PDP_GROUP, PDP_SUBGROUP);
+        assertTrue("subgroup msg " + message, message.appliesTo(PDP_NAME, PDP_GROUP, PDP_SUBGROUP));
+
+        /*
+         * Test cases where the subgroup does not match.
+         */
+        message = makeMessage(null, PDP_GROUP, PDP_SUBGROUP);
+
+        for (String pdpSubgroup : new String[] {null, DIFFERENT}) {
+            assertFalse("subgroup msg " + message + " pdp subgroup " + pdpSubgroup,
+                            message.appliesTo(PDP_NAME, PDP_GROUP, pdpSubgroup));
+        }
+    }
+
+    @Test
+    public void testAppliesTo_NullPdpName() {
+        message = makeMessage(PDP_NAME, PDP_GROUP, PDP_SUBGROUP);
+
+        assertThatThrownBy(() -> message.appliesTo(null, PDP_GROUP, PDP_SUBGROUP))
+                        .isInstanceOf(NullPointerException.class);
+
+    }
+
+    private PdpMessage makeMessage(String pdpName, String pdpGroup, String pdpSubgroup) {
+        PdpMessage msg = new PdpMessage(PdpMessageType.PDP_STATE_CHANGE);
+
+        msg.setName(pdpName);
+        msg.setPdpGroup(pdpGroup);
+        msg.setPdpSubgroup(pdpSubgroup);
+
+        return msg;
     }
 }