import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Optional;
 import java.util.Set;
 import java.util.function.BiPredicate;
+import java.util.stream.Collectors;
 import org.onap.policy.models.pap.concepts.PolicyStatus;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier;
 
         super();
     }
 
+    /**
+     * Gets the status of all policies being tracked.
+     *
+     * @return the status of all policies
+     */
+    public List<PolicyStatus> getStatus() {
+        return policy2data.entrySet().stream().map(this::makeStatus).collect(Collectors.toList());
+    }
+
+    /**
+     * Gets the status of all versions of a policy.
+     *
+     * @param policyId ID of the policy of interest, without the version
+     * @return the status of all versions of the policy having the given ID
+     */
+    public List<PolicyStatus> getStatus(String policyId) {
+        // version is not specified - have to scan the whole list
+        return policy2data.entrySet().stream().filter(ent -> ent.getKey().getName().equals(policyId))
+                        .map(this::makeStatus).collect(Collectors.toList());
+    }
+
+    /**
+     * Gets the status of a particular policy.
+     *
+     * @param ident identifier of the policy of interest
+     * @return the status of the given policy, or empty if the policy is not found
+     */
+    public Optional<PolicyStatus> getStatus(ToscaPolicyIdentifier ident) {
+        ToscaPolicyIdentifier ident2 = new ToscaPolicyIdentifier(ident.getName(), ident.getVersion());
+        PolicyTrackerData data = policy2data.get(ident2);
+        return Optional.ofNullable(data == null ? null : makeStatus(ident2, data));
+    }
+
     /**
      * Adds data to the tracker.
      *
             }
 
             // this policy is complete - notify
-            statusList.add(makeStatus(policyId, data));
+            statusList.add(makeStatus(ent));
 
             if (shouldRemove(data)) {
                 iter.remove();
      */
     protected abstract boolean shouldRemove(PolicyTrackerData data);
 
+    /**
+     * Makes a status notification for the given policy entry.
+     *
+     * @param entry policy entry
+     * @return a new status notification
+     */
+    private PolicyStatus makeStatus(Map.Entry<ToscaPolicyIdentifier, PolicyTrackerData> entry) {
+        return makeStatus(entry.getKey(), entry.getValue());
+    }
+
     /**
      * Makes a status notification for the given policy.
      *
      * @param data data to be used to set the status fields
      * @return a new status notification
      */
-    private synchronized PolicyStatus makeStatus(ToscaPolicyIdentifier policyId, PolicyTrackerData data) {
+    private PolicyStatus makeStatus(ToscaPolicyIdentifier policyId, PolicyTrackerData data) {
 
         PolicyStatus status = new PolicyStatus(data.getPolicyType(), policyId);
         data.putValuesInto(status);
 
 package org.onap.policy.pap.main.notification;
 
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
+import java.util.stream.Collectors;
+import org.onap.policy.models.base.PfModelException;
 import org.onap.policy.models.pap.concepts.PolicyNotification;
+import org.onap.policy.models.pap.concepts.PolicyStatus;
+import org.onap.policy.models.pdp.concepts.Pdp;
+import org.onap.policy.models.pdp.concepts.PdpGroup;
+import org.onap.policy.models.pdp.concepts.PdpSubGroup;
+import org.onap.policy.models.provider.PolicyModelsProvider;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyFilter;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
+import org.onap.policy.pap.main.PolicyModelsProviderFactoryWrapper;
 import org.onap.policy.pap.main.comm.Publisher;
 import org.onap.policy.pap.main.comm.QueueToken;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Notifier for completion of policy updates.
  */
 public class PolicyNotifier {
+    private static final Logger logger = LoggerFactory.getLogger(PolicyNotifier.class);
+
     /**
      * Notification publisher.
      */
 
 
     /**
-     * Constructs the object.
+     * Constructs the object. Loads all deployed policies into the internal cache.
      *
      * @param publisher notification publisher
+     * @param daoFactory factory used to load policy deployment data from the DB
+     * @throws PfModelException if a DB error occurs
      */
-    public PolicyNotifier(Publisher<PolicyNotification> publisher) {
+    public PolicyNotifier(Publisher<PolicyNotification> publisher, PolicyModelsProviderFactoryWrapper daoFactory)
+                    throws PfModelException {
+
         this.publisher = publisher;
+
+        try (PolicyModelsProvider dao = daoFactory.create()) {
+            Map<ToscaPolicyIdentifier, ToscaPolicyTypeIdentifier> id2type = loadPolicyTypes(dao);
+            loadPolicies(dao, id2type);
+        }
+    }
+
+    /**
+     * Loads policy types from the DB.
+     *
+     * @param dao provider used to retrieve policies from the DB
+     * @return a mapping from policy id to policy type
+     * @throws PfModelException if a DB error occurs
+     */
+    private Map<ToscaPolicyIdentifier, ToscaPolicyTypeIdentifier> loadPolicyTypes(PolicyModelsProvider dao)
+                    throws PfModelException {
+
+        Map<ToscaPolicyIdentifier, ToscaPolicyTypeIdentifier> id2type = new HashMap<>();
+
+        for (ToscaPolicy policy : dao.getFilteredPolicyList(ToscaPolicyFilter.builder().build())) {
+            id2type.put(policy.getIdentifier(), policy.getTypeIdentifier());
+        }
+
+        return id2type;
+    }
+
+    /**
+     * Loads deployed policies.
+     *
+     * @param id2type mapping from policy id to policy type
+     * @param dao provider used to retrieve policies from the DB
+     * @throws PfModelException if a DB error occurs
+     */
+    private void loadPolicies(PolicyModelsProvider dao, Map<ToscaPolicyIdentifier, ToscaPolicyTypeIdentifier> id2type)
+                    throws PfModelException {
+        for (PdpGroup group : dao.getPdpGroups(null)) {
+            for (PdpSubGroup subgrp : group.getPdpSubgroups()) {
+                loadPolicies(id2type, group, subgrp);
+            }
+        }
+    }
+
+    /**
+     * Loads a subgroup's deployed policies.
+     *
+     * @param id2type maps a policy id to its type
+     * @param group group containing the subgroup
+     * @param subgrp subgroup whose policies are to be loaded
+     */
+    private void loadPolicies(Map<ToscaPolicyIdentifier, ToscaPolicyTypeIdentifier> id2type, PdpGroup group,
+                    PdpSubGroup subgrp) {
+
+        for (ToscaPolicyIdentifier policyId : subgrp.getPolicies()) {
+
+            ToscaPolicyTypeIdentifier type = id2type.get(policyId);
+            if (type == null) {
+                logger.error("group {}:{} refers to non-existent policy {}:{}", group.getName(), subgrp.getPdpType(),
+                                policyId.getName(), policyId.getVersion());
+                continue;
+            }
+
+            PolicyPdpNotificationData data = new PolicyPdpNotificationData(policyId, type);
+            data.addAll(subgrp.getPdpInstances().stream().map(Pdp::getInstanceId).collect(Collectors.toList()));
+            deployTracker.addData(data);
+        }
+    }
+
+    /**
+     * Gets the status of all deployed policies.
+     *
+     * @return the status of all deployed policies
+     */
+    public synchronized List<PolicyStatus> getStatus() {
+        return deployTracker.getStatus();
+    }
+
+    /**
+     * Gets the status of a particular deployed policy.
+     *
+     * @param policyId ID of the policy of interest, without the version
+     * @return the status of all deployed policies matching the given identifier
+     */
+    public synchronized List<PolicyStatus> getStatus(String policyId) {
+        return deployTracker.getStatus(policyId);
+    }
+
+    /**
+     * Gets the status of a particular deployed policy.
+     *
+     * @param ident identifier of the policy of interest
+     * @return the status of the given policy, or empty if the policy is not found
+     */
+    public synchronized Optional<PolicyStatus> getStatus(ToscaPolicyIdentifier ident) {
+        return deployTracker.getStatus(ident);
     }
 
     /**
 
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP PAP
+ * ================================================================================
+ * Copyright (C) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.pap.main.rest;
+
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.Authorization;
+import io.swagger.annotations.Extension;
+import io.swagger.annotations.ExtensionProperty;
+import io.swagger.annotations.ResponseHeader;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.Response;
+import org.onap.policy.common.utils.services.Registry;
+import org.onap.policy.models.pap.concepts.PolicyStatus;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier;
+import org.onap.policy.pap.main.PapConstants;
+import org.onap.policy.pap.main.notification.PolicyNotifier;
+
+/**
+ * Class to provide REST end points for PAP component to retrieve the status of deployed
+ * policies.
+ */
+public class PolicyStatusControllerV1 extends PapRestControllerV1 {
+    private final PolicyNotifier notifier;
+
+    public PolicyStatusControllerV1() {
+        this.notifier = Registry.get(PapConstants.REG_POLICY_NOTIFIER, PolicyNotifier.class);
+    }
+
+    /**
+     * Queries status of all deployed policies.
+     *
+     * @param requestId request ID used in ONAP logging
+     * @return a response
+     */
+    // @formatter:off
+    @GET
+    @Path("policies/deployed")
+    @ApiOperation(value = "Queries status of all deployed policies",
+        notes = "Queries status of all deployed policies, returning success and failure counts of the PDPs",
+        responseContainer = "List", response = PolicyStatus.class,
+        tags = {"Policy Administration (PAP) API"},
+        authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+        responseHeaders = {
+            @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
+                            response = String.class),
+            @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
+                            response = String.class),
+            @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
+                            response = String.class),
+            @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
+                            response = UUID.class)},
+        extensions = {@Extension(name = EXTENSION_NAME,
+            properties = {@ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+                @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)})})
+    @ApiResponses(value = {@ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+                    @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+                    @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)})
+    // @formatter:on
+
+    public Response queryAllDeployedPolicies(
+                    @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) final UUID requestId) {
+
+        return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.OK)), requestId)
+                        .entity(notifier.getStatus()).build();
+    }
+
+
+    /**
+     * Queries status of specific deployed policies.
+     *
+     * @param requestId request ID used in ONAP logging
+     * @return a response
+     */
+    // @formatter:off
+    @GET
+    @Path("policies/deployed/{name}")
+    @ApiOperation(value = "Queries status of specific deployed policies",
+        notes = "Queries status of specific deployed policies, returning success and failure counts of the PDPs",
+        responseContainer = "List", response = PolicyStatus.class,
+        tags = {"Policy Administration (PAP) API"},
+        authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+        responseHeaders = {
+            @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
+                            response = String.class),
+            @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
+                            response = String.class),
+            @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
+                            response = String.class),
+            @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
+                            response = UUID.class)},
+        extensions = {@Extension(name = EXTENSION_NAME,
+            properties = {@ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+                @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)})})
+    @ApiResponses(value = {@ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+                    @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+                    @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)})
+    // @formatter:on
+
+    public Response queryDeployedPolicies(
+                    @ApiParam(value = "Policy Id", required = true) @PathParam("name") String name,
+                    @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) final UUID requestId) {
+
+        List<PolicyStatus> result = notifier.getStatus(name);
+        if (result.isEmpty()) {
+            return makeNotFoundResponse(requestId);
+
+        } else {
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.OK)), requestId)
+                            .entity(result).build();
+        }
+    }
+
+
+    /**
+     * Queries status of a specific deployed policy.
+     *
+     * @param requestId request ID used in ONAP logging
+     * @return a response
+     */
+    // @formatter:off
+    @GET
+    @Path("policies/deployed/{name}/{version}")
+    @ApiOperation(value = "Queries status of a specific deployed policy",
+        notes = "Queries status of a specific deployed policy, returning success and failure counts of the PDPs",
+        response = PolicyStatus.class,
+        tags = {"Policy Administration (PAP) API"},
+        authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+        responseHeaders = {
+            @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
+                            response = String.class),
+            @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
+                            response = String.class),
+            @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
+                            response = String.class),
+            @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
+                            response = UUID.class)},
+        extensions = {@Extension(name = EXTENSION_NAME,
+            properties = {@ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+                @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)})})
+    @ApiResponses(value = {@ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+                    @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+                    @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)})
+    // @formatter:on
+
+    public Response queryDeployedPolicy(@ApiParam(value = "Policy Id", required = true) @PathParam("name") String name,
+                    @ApiParam(value = "Policy Version", required = true) @PathParam("version") String version,
+                    @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) final UUID requestId) {
+
+        ToscaPolicyIdentifier ident = new ToscaPolicyIdentifier(name, version);
+        Optional<PolicyStatus> result = notifier.getStatus(ident);
+        if (result.isPresent()) {
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.OK)), requestId)
+                            .entity(result.get()).build();
+
+        } else {
+            return makeNotFoundResponse(requestId);
+        }
+    }
+
+
+    /**
+     * Makes a "not found" response.
+     *
+     * @param requestId request ID
+     * @return a "not found" response
+     */
+    private Response makeNotFoundResponse(final UUID requestId) {
+        return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.NOT_FOUND)), requestId)
+                        .build();
+    }
+}
 
 import org.onap.policy.pap.main.rest.PdpGroupHealthCheckControllerV1;
 import org.onap.policy.pap.main.rest.PdpGroupQueryControllerV1;
 import org.onap.policy.pap.main.rest.PdpGroupStateChangeControllerV1;
+import org.onap.policy.pap.main.rest.PolicyStatusControllerV1;
 import org.onap.policy.pap.main.rest.StatisticsRestControllerV1;
 import org.onap.policy.pap.main.rest.depundep.PdpGroupDeleteControllerV1;
 import org.onap.policy.pap.main.rest.depundep.PdpGroupDeployControllerV1;
             () -> {
                 notifyPub.set(new Publisher<>(PapConstants.TOPIC_POLICY_NOTIFICATION));
                 startThread(notifyPub.get());
-                notifier.set(new PolicyNotifier(notifyPub.get()));
+                notifier.set(new PolicyNotifier(notifyPub.get(), daoFactory.get()));
             },
             () -> notifyPub.get().stop());
 
                                 PdpGroupDeleteControllerV1.class,
                                 PdpGroupStateChangeControllerV1.class,
                                 PdpGroupQueryControllerV1.class,
-                                PdpGroupHealthCheckControllerV1.class);
+                                PdpGroupHealthCheckControllerV1.class,
+                                PolicyStatusControllerV1.class);
                 restServer.set(server);
                 restServer.get().start();
             },
 
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
 import org.junit.Before;
 import org.junit.Test;
 import org.onap.policy.models.pap.concepts.PolicyStatus;
         tracker = new MyTracker();
     }
 
+    @Test
+    public void testGetStatus() {
+        tracker.addData(makeData(policy1, PDP1, PDP2));
+        tracker.addData(makeData(policy2, PDP2));
+
+        List<PolicyStatus> statusList = tracker.getStatus();
+        assertEquals(2, statusList.size());
+
+        Set<String> names = statusList.stream().map(PolicyStatus::getPolicyId).collect(Collectors.toSet());
+        assertTrue(names.contains(policy1.getName()));
+        assertTrue(names.contains(policy2.getName()));
+    }
+
+    @Test
+    public void testGetStatusString() {
+        tracker.addData(makeData(policy1, PDP1, PDP2));
+        tracker.addData(makeData(policy2, PDP2));
+
+        policy3 = new ToscaPolicyIdentifier(policy1.getName(), policy1.getVersion() + "0");
+        tracker.addData(makeData(policy3, PDP3));
+
+        List<PolicyStatus> statusList = tracker.getStatus(policy1.getName());
+        assertEquals(2, statusList.size());
+
+        Set<ToscaPolicyIdentifier> idents =
+                        statusList.stream().map(PolicyStatus::getPolicy).collect(Collectors.toSet());
+        assertTrue(idents.contains(policy1));
+        assertTrue(idents.contains(policy3));
+    }
+
+    @Test
+    public void testGetStatusToscaPolicyIdentifier() {
+        tracker.addData(makeData(policy1, PDP1, PDP2));
+        tracker.addData(makeData(policy2, PDP2));
+
+        policy3 = new ToscaPolicyIdentifier(policy1.getName(), policy1.getVersion() + "0");
+        tracker.addData(makeData(policy3, PDP3));
+
+        Optional<PolicyStatus> status = tracker.getStatus(policy1);
+        assertTrue(status.isPresent());
+
+        assertEquals(policy1, status.get().getPolicy());
+
+        // check not-found case
+        status = tracker.getStatus(policy4);
+        assertFalse(status.isPresent());
+    }
+
     @Test
     public void testAddData() {
         tracker.addData(makeData(policy1, PDP1, PDP2));
     }
 
     /**
-     * Tests removeData() when the subclass indicates that the policy should NOT be removed.
+     * Tests removeData() when the subclass indicates that the policy should NOT be
+     * removed.
      */
     @Test
     public void testRemoveDataDoNotRemovePolicy() {
 
 package org.onap.policy.pap.main.notification;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Optional;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.stubbing.Answer;
+import org.onap.policy.models.base.PfModelException;
 import org.onap.policy.models.pap.concepts.PolicyNotification;
 import org.onap.policy.models.pap.concepts.PolicyStatus;
+import org.onap.policy.models.pdp.concepts.Pdp;
+import org.onap.policy.models.pdp.concepts.PdpGroup;
+import org.onap.policy.models.pdp.concepts.PdpSubGroup;
+import org.onap.policy.models.provider.PolicyModelsProvider;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
+import org.onap.policy.pap.main.PolicyModelsProviderFactoryWrapper;
+import org.onap.policy.pap.main.PolicyPapRuntimeException;
 import org.onap.policy.pap.main.comm.Publisher;
 import org.onap.policy.pap.main.comm.QueueToken;
 
     @Mock
     private Publisher<PolicyNotification> publisher;
 
+    @Mock
+    private PolicyModelsProviderFactoryWrapper daoFactory;
+
+    @Mock
+    private PolicyModelsProvider dao;
+
     @Mock
     private PolicyDeployTracker deploy;
 
 
         super.setUp();
 
+        try {
+            when(daoFactory.create()).thenReturn(dao);
+            when(dao.getPdpGroups(null)).thenReturn(Collections.emptyList());
+
+            notifier = new MyNotifier(publisher);
+
+        } catch (PfModelException e) {
+            throw new PolicyPapRuntimeException(e);
+        }
+    }
+
+    @Test
+    public void testLoadPoliciesPolicyModelsProviderFactoryWrapper() throws PfModelException {
+        final PdpGroup group1 = makeGroup("my group #1", makeSubGroup("sub #1 A", 2, policy1, policy4),
+                        makeSubGroup("sub #1 B", 1, policy2));
+
+        // one policy is a duplicate
+        final PdpGroup group2 = makeGroup("my group #2", makeSubGroup("sub #2 A", 1, policy1, policy3));
+
+        when(dao.getPdpGroups(null)).thenReturn(Arrays.asList(group1, group2));
+
+        ToscaPolicyTypeIdentifier type2 = new ToscaPolicyTypeIdentifier("my other type", "8.8.8");
+
+        // note: no mapping for policy4
+        when(dao.getFilteredPolicyList(any())).thenReturn(Arrays.asList(makePolicy(policy1, type),
+                        makePolicy(policy2, type2), makePolicy(policy3, type)));
+
+        // load it
         notifier = new MyNotifier(publisher);
+
+        ArgumentCaptor<PolicyPdpNotificationData> captor = ArgumentCaptor.forClass(PolicyPdpNotificationData.class);
+
+        // should have added policy1, policy2, policy1 (duplicate), policy3, but not
+        // policy4
+        verify(deploy, times(4)).addData(captor.capture());
+
+        Iterator<PolicyPdpNotificationData> iter = captor.getAllValues().iterator();
+        PolicyPdpNotificationData data = iter.next();
+        assertEquals(policy1, data.getPolicyId());
+        assertEquals(type, data.getPolicyType());
+        assertEquals("[sub #1 A 0, sub #1 A 1]", data.getPdps().toString());
+
+        data = iter.next();
+        assertEquals(policy2, data.getPolicyId());
+        assertEquals(type2, data.getPolicyType());
+        assertEquals("[sub #1 B 0]", data.getPdps().toString());
+
+        data = iter.next();
+        assertEquals(policy1, data.getPolicyId());
+        assertEquals(type, data.getPolicyType());
+        assertEquals("[sub #2 A 0]", data.getPdps().toString());
+
+        data = iter.next();
+        assertEquals(policy3, data.getPolicyId());
+        assertEquals(type, data.getPolicyType());
+        assertEquals("[sub #2 A 0]", data.getPdps().toString());
+    }
+
+    private ToscaPolicy makePolicy(ToscaPolicyIdentifier policyId, ToscaPolicyTypeIdentifier type) {
+        ToscaPolicy policy = new ToscaPolicy();
+
+        policy.setName(policyId.getName());
+        policy.setVersion(policyId.getVersion());
+        policy.setType(type.getName());
+        policy.setTypeVersion(type.getVersion());
+
+        return policy;
+    }
+
+    private PdpGroup makeGroup(String name, PdpSubGroup... subgrps) {
+        final PdpGroup group = new PdpGroup();
+        group.setName(name);
+
+        group.setPdpSubgroups(Arrays.asList(subgrps));
+
+        return group;
+    }
+
+    private PdpSubGroup makeSubGroup(String name, int numPdps, ToscaPolicyIdentifier... policies) {
+        final PdpSubGroup subgrp = new PdpSubGroup();
+        subgrp.setPdpType(name);
+        subgrp.setPdpInstances(new ArrayList<>(numPdps));
+
+        for (int x = 0; x < numPdps; ++x) {
+            Pdp pdp = new Pdp();
+            pdp.setInstanceId(name + " " + x);
+
+            subgrp.getPdpInstances().add(pdp);
+        }
+
+        subgrp.setPolicies(Arrays.asList(policies));
+
+        return subgrp;
+    }
+
+    @Test
+    public void testGetStatus() {
+        List<PolicyStatus> statusList = Arrays.asList(status1);
+        when(deploy.getStatus()).thenReturn(statusList);
+
+        assertSame(statusList, notifier.getStatus());
+    }
+
+    @Test
+    public void testGetStatusString() {
+        List<PolicyStatus> statusList = Arrays.asList(status1);
+        when(deploy.getStatus("a policy")).thenReturn(statusList);
+
+        assertSame(statusList, notifier.getStatus("a policy"));
+    }
+
+    @Test
+    public void testGetStatusToscaPolicyIdentifier() {
+        Optional<PolicyStatus> status = Optional.of(status1);
+        when(deploy.getStatus(policy1)).thenReturn(status);
+
+        assertSame(status, notifier.getStatus(policy1));
     }
 
     @Test
     }
 
     @Test
-    public void testMakeDeploymentTracker_testMakeUndeploymentTracker() {
+    public void testMakeDeploymentTracker_testMakeUndeploymentTracker() throws PfModelException {
         // make real object, which will invoke the real makeXxx() methods
-        new PolicyNotifier(publisher).removePdp(PDP1);
+        new PolicyNotifier(publisher, daoFactory).removePdp(PDP1);
 
         verify(publisher, never()).enqueue(any());
     }
 
     private class MyNotifier extends PolicyNotifier {
 
-        public MyNotifier(Publisher<PolicyNotification> publisher) {
-            super(publisher);
+        public MyNotifier(Publisher<PolicyNotification> publisher) throws PfModelException {
+            super(publisher, daoFactory);
         }
 
         @Override
 
  */
 public class CommonPapRestServer {
 
+    protected static final String CONFIG_FILE = "src/test/resources/parameters/TestConfigParams.json";
+
     private static final Logger LOGGER = LoggerFactory.getLogger(CommonPapRestServer.class);
 
     private static String KEYSTORE = System.getProperty("user.dir") + "/src/test/resources/ssl/policy-keystore";
      */
     @BeforeClass
     public static void setUpBeforeClass() throws Exception {
+        setUpBeforeClass(true);
+    }
+
+    /**
+     * Allocates a port for the server, writes a config file, and then starts Main, if
+     * specified.
+     *
+     * @param shouldStart {@code true} if Main should be started, {@code false} otherwise
+     * @throws Exception if an error occurs
+     */
+    public static void setUpBeforeClass(boolean shouldStart) throws Exception {
         port = NetworkUtil.allocPort();
 
         httpsPrefix = "https://localhost:" + port + "/";
 
         CommonTestData.newDb();
 
-        startMain();
+        if (shouldStart) {
+            startMain();
+        }
     }
 
     /**
     private static void makeConfigFile() throws Exception {
         String json = new CommonTestData().getPapParameterGroupAsString(port);
 
-        File file = new File("src/test/resources/parameters/TestConfigParams.json");
+        File file = new File(CONFIG_FILE);
         file.deleteOnExit();
 
         try (FileOutputStream output = new FileOutputStream(file)) {
      *
      * @throws Exception if an error occurs
      */
-    private static void startMain() throws Exception {
+    protected static void startMain() throws Exception {
         Registry.newRegistry();
 
         // make sure port is available
         systemProps.put("javax.net.ssl.keyStorePassword", "Pol1cy_0nap");
         System.setProperties(systemProps);
 
-        final String[] papConfigParameters = { "-c", "src/test/resources/parameters/TestConfigParams.json" };
+        final String[] papConfigParameters = { "-c", CONFIG_FILE };
 
         main = new Main(papConfigParameters);
 
 
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2019 Nordix Foundation.
+ *  Modifications Copyright (C) 2019 AT&T Intellectual Property.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.pap.main.rest;
+
+import static org.junit.Assert.assertEquals;
+
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.core.Response;
+import org.junit.Test;
+
+/**
+ * Note: this tests failure cases; success cases are tested by tests in the "e2e" package.
+ */
+public class TestPolicyStatusControllerV1 extends CommonPapRestServer {
+
+    private static final String POLICY_STATUS_ENDPOINT = "policies/deployed";
+
+    @Test
+    public void testSwagger() throws Exception {
+        super.testSwagger(POLICY_STATUS_ENDPOINT);
+
+        super.testSwagger(POLICY_STATUS_ENDPOINT + "/{name}");
+        super.testSwagger(POLICY_STATUS_ENDPOINT + "/{name}/{version}");
+    }
+
+    @Test
+    public void queryAllDeployedPolicies() throws Exception {
+        String uri = POLICY_STATUS_ENDPOINT;
+
+        // verify it fails when no authorization info is included
+        checkUnauthRequest(uri, req -> req.get());
+    }
+
+    @Test
+    public void testQueryDeployedPolicies() throws Exception {
+        String uri = POLICY_STATUS_ENDPOINT + "/my-name";
+
+        Invocation.Builder invocationBuilder = sendRequest(uri);
+        Response rawresp = invocationBuilder.get();
+        assertEquals(Response.Status.NOT_FOUND.getStatusCode(), rawresp.getStatus());
+
+        // verify it fails when no authorization info is included
+        checkUnauthRequest(uri, req -> req.get());
+    }
+
+    @Test
+    public void queryDeployedPolicy() throws Exception {
+        String uri = POLICY_STATUS_ENDPOINT + "/my-name/1.2.3";
+
+        Invocation.Builder invocationBuilder = sendRequest(uri);
+        Response rawresp = invocationBuilder.get();
+        assertEquals(Response.Status.NOT_FOUND.getStatusCode(), rawresp.getStatus());
+
+        // verify it fails when no authorization info is included
+        checkUnauthRequest(uri, req -> req.get());
+    }
+}
 
 import org.onap.policy.common.utils.coder.CoderException;
 import org.onap.policy.common.utils.coder.StandardCoder;
 import org.onap.policy.common.utils.resources.ResourceUtils;
-import org.onap.policy.common.utils.services.Registry;
 import org.onap.policy.models.base.PfModelException;
 import org.onap.policy.models.pdp.concepts.PdpGroups;
 import org.onap.policy.models.provider.PolicyModelsProvider;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
-import org.onap.policy.pap.main.PapConstants;
 import org.onap.policy.pap.main.PolicyModelsProviderFactoryWrapper;
 import org.onap.policy.pap.main.PolicyPapRuntimeException;
+import org.onap.policy.pap.main.parameters.PapParameterGroup;
 import org.onap.policy.pap.main.rest.CommonPapRestServer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
      */
     @BeforeClass
     public static void setUpBeforeClass() throws Exception {
-        CommonPapRestServer.setUpBeforeClass();
+        setUpBeforeClass(true);
+    }
 
-        daoFactory = Registry.get(PapConstants.REG_PAP_DAO_FACTORY, PolicyModelsProviderFactoryWrapper.class);
+    /**
+     * Starts Main, if specified, and connects to the DB.
+     *
+     * @param shouldStart {@code true} if Main should be started, {@code false} otherwise
+     * @throws Exception if an error occurs
+     */
+    public static void setUpBeforeClass(boolean shouldStart) throws Exception {
+        CommonPapRestServer.setUpBeforeClass(shouldStart);
 
-        try {
-            dbConn = daoFactory.create();
-        } catch (PfModelException e) {
-            throw new PolicyPapRuntimeException("cannot connect to DB", e);
-        }
+        PapParameterGroup params = new StandardCoder().decode(new File(CONFIG_FILE), PapParameterGroup.class);
+        daoFactory = new PolicyModelsProviderFactoryWrapper(params.getDatabaseProviderParameters());
+        dbConn = daoFactory.create();
     }
 
     /**
 
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP PAP
+ * ================================================================================
+ * Copyright (C) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.pap.main.rest.e2e;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.Response;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.policy.models.pap.concepts.PolicyStatus;
+
+public class PolicyStatusTest extends End2EndBase {
+    private static final String POLICY_STATUS_ENDPOINT = "policies/deployed";
+
+    /**
+     * Starts Main and adds policies to the DB.
+     *
+     * @throws Exception if an error occurs
+     */
+    @BeforeClass
+    public static void setUpBeforeClass() throws Exception {
+        // don't start Main until AFTER we add the policies to the DB
+        End2EndBase.setUpBeforeClass(false);
+
+        addToscaPolicyTypes("monitoring.policy-type.yaml");
+        addToscaPolicies("monitoring.policy.yaml");
+        addGroups("policyStatus.json");
+
+        startMain();
+    }
+
+    @Test
+    public void testQueryAllDeployedPolicies() throws Exception {
+        String uri = POLICY_STATUS_ENDPOINT;
+
+        Invocation.Builder invocationBuilder = sendRequest(uri);
+        Response rawresp = invocationBuilder.get();
+        assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
+
+        List<PolicyStatus> resp = rawresp.readEntity(new GenericType<List<PolicyStatus>>() {});
+        assertEquals(1, resp.size());
+
+        PolicyStatus status = resp.get(0);
+        assertEquals("onap.restart.tca", status.getPolicyId());
+        assertEquals("1.0.0", status.getPolicyVersion());
+        assertEquals("onap.policies.monitoring.cdap.tca.hi.lo.app", status.getPolicyTypeId());
+        assertEquals("1.0.0", status.getPolicyTypeVersion());
+        assertEquals(0, status.getFailureCount());
+        assertEquals(1, status.getIncompleteCount());
+        assertEquals(0, status.getSuccessCount());
+    }
+
+    @Test
+    public void testQueryDeployedPolicies() throws Exception {
+        String uri = POLICY_STATUS_ENDPOINT + "/onap.restart.tca";
+
+        Invocation.Builder invocationBuilder = sendRequest(uri);
+        Response rawresp = invocationBuilder.get();
+        assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
+
+        List<PolicyStatus> resp = rawresp.readEntity(new GenericType<List<PolicyStatus>>() {});
+        assertEquals(1, resp.size());
+
+        PolicyStatus status = resp.get(0);
+        assertEquals("onap.restart.tca", status.getPolicyId());
+        assertEquals("1.0.0", status.getPolicyVersion());
+        assertEquals("onap.policies.monitoring.cdap.tca.hi.lo.app", status.getPolicyTypeId());
+        assertEquals("1.0.0", status.getPolicyTypeVersion());
+        assertEquals(0, status.getFailureCount());
+        assertEquals(1, status.getIncompleteCount());
+        assertEquals(0, status.getSuccessCount());
+    }
+
+    @Test
+    public void testQueryDeployedPolicy() throws Exception {
+        String uri = POLICY_STATUS_ENDPOINT + "/onap.restart.tca/1.0.0";
+
+        Invocation.Builder invocationBuilder = sendRequest(uri);
+        Response rawresp = invocationBuilder.get();
+        assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
+
+        PolicyStatus status = rawresp.readEntity(PolicyStatus.class);
+        assertEquals("onap.restart.tca", status.getPolicyId());
+        assertEquals("1.0.0", status.getPolicyVersion());
+        assertEquals("onap.policies.monitoring.cdap.tca.hi.lo.app", status.getPolicyTypeId());
+        assertEquals("1.0.0", status.getPolicyTypeVersion());
+        assertEquals(0, status.getFailureCount());
+        assertEquals(1, status.getIncompleteCount());
+        assertEquals(0, status.getSuccessCount());
+    }
+}
 
--- /dev/null
+{
+    "groups": [
+        {
+            "name": "policyStatus",
+            "pdpGroupState": "ACTIVE",
+            "pdpSubgroups": [
+                {
+                    "pdpType": "pdpTypeA",
+                    "desiredInstanceCount": 2,
+                    "pdpInstances": [
+                        {
+                            "instanceId": "pdpA_1",
+                            "pdpState": "ACTIVE",
+                            "healthy": "HEALTHY"
+                        },
+                        {
+                            "instanceId": "pdpA_2",
+                            "pdpState": "ACTIVE",
+                            "healthy": "HEALTHY"
+                        }
+                    ],
+                    "supportedPolicyTypes": [
+                        {
+                            "name": "onap.policies.monitoring.cdap.tca.hi.lo.app",
+                            "version": "1.0.0"
+                        }
+                    ],
+                    "policies": []
+                },
+                {
+                    "pdpType": "pdpTypeB",
+                    "desiredInstanceCount": 1,
+                    "pdpInstances": [
+                        {
+                            "instanceId": "pdpB_1",
+                            "pdpState": "ACTIVE",
+                            "healthy": "HEALTHY"
+                        }
+                    ],
+                    "supportedPolicyTypes": [
+                        {
+                            "name": "onap.policies.monitoring.cdap.tca.hi.lo.app",
+                            "version": "1.0.0"
+                        }
+                    ],
+                    "policies": [
+                        {
+                            "name": "onap.restart.tca",
+                            "version": "1.0.0"
+                        }
+                    ]
+                }
+            ]
+        }
+    ]
+}