6b291c6a2b0a142eba0e91f9b867e3157391115d
[policy/xacml-pdp.git] / tutorials / tutorial-enforcement / src / main / java / org / onap / policy / tutorial / policyenforcement / App.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  * ============LICENSE_END=========================================================
17  */
18
19 package org.onap.policy.tutorial.policyenforcement;
20
21 import java.util.Arrays;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.Map;
25 import java.util.Map.Entry;
26 import java.util.Scanner;
27 import javax.ws.rs.client.Entity;
28 import javax.ws.rs.core.MediaType;
29 import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
30 import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager;
31 import org.onap.policy.common.endpoints.event.comm.TopicListener;
32 import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams;
33 import org.onap.policy.common.endpoints.http.client.HttpClient;
34 import org.onap.policy.common.endpoints.http.client.HttpClientConfigException;
35 import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance;
36 import org.onap.policy.common.endpoints.parameters.TopicParameterGroup;
37 import org.onap.policy.common.endpoints.parameters.TopicParameters;
38 import org.onap.policy.common.utils.coder.CoderException;
39 import org.onap.policy.common.utils.coder.StandardCoder;
40 import org.onap.policy.models.decisions.concepts.DecisionRequest;
41 import org.onap.policy.models.decisions.concepts.DecisionResponse;
42 import org.onap.policy.models.pap.concepts.PolicyNotification;
43 import org.onap.policy.models.pap.concepts.PolicyStatus;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 public class App extends Thread implements TopicListener {
48     private static Logger logger                           = LoggerFactory.getLogger(App.class);
49     private static final String MY_POLICYTYPEID = "onap.policies.monitoring.MyAnalytic";
50     private String xacmlPdpHost;
51     private String xacmlPdpPort;
52     private DecisionRequest decisionRequest = new DecisionRequest();
53     private Integer requestId = 1;
54     private HttpClient client = null;
55
56     /**
57      * Constructor.
58      *
59      * @param args Command line arguments
60      */
61     public App(String[] args) {
62         xacmlPdpHost = args[0];
63         xacmlPdpPort = args[1];
64
65         var params = new TopicParameters();
66         params.setTopicCommInfrastructure("dmaap");
67         params.setFetchLimit(1);
68         params.setFetchTimeout(5000);
69         params.setTopic("POLICY-NOTIFICATION");
70         params.setServers(Arrays.asList(args[2] + ":" + args[3]));
71         var topicParams = new TopicParameterGroup();
72         topicParams.setTopicSources(Arrays.asList(params));
73
74         TopicEndpointManager.getManager().addTopics(topicParams);
75         TopicEndpointManager.getManager().getDmaapTopicSource("POLICY-NOTIFICATION").register(this);
76
77         decisionRequest.setOnapComponent("myComponent");
78         decisionRequest.setOnapName("myName");
79         decisionRequest.setOnapInstance("myInstanceId");
80         decisionRequest.setAction("configure");
81         Map<String, Object> resources = new HashMap<>();
82         resources.put("policy-type", MY_POLICYTYPEID);
83         decisionRequest.setResource(resources);
84     }
85
86     /**
87      * Thread run method that creates a connection and gets an initial Decision on which policy(s)
88      * we should be enforcing.
89      * Then sits waiting for the user to enter q or Q from the keyboard to quit. While waiting,
90      * listen on Dmaap topic for notification that the policy has changed.
91      */
92     @Override
93     public void run() {
94         logger.info("running - type q to stdin to quit");
95         try {
96             client = HttpClientFactoryInstance.getClientFactory().build(BusTopicParams.builder()
97                     .clientName("myClientName").useHttps(true).allowSelfSignedCerts(true)
98                     .hostname(xacmlPdpHost).port(Integer.parseInt(xacmlPdpPort))
99                     .userName("healthcheck").password("zb!XztG34").basePath("policy/pdpx/v1")
100                     .managed(true)
101                     .serializationProvider("org.onap.policy.common.gson.GsonMessageBodyHandler")
102                     .build());
103         } catch (NumberFormatException | HttpClientConfigException e) {
104             logger.error("Could not create Http client", e);
105             return;
106         }
107
108         Map<String, Object> policies = getDecision(client, this.decisionRequest);
109         if (policies.isEmpty()) {
110             logger.info("Not enforcing any policies to start");
111         }
112         for (Entry<String, Object> entrySet : policies.entrySet()) {
113             logger.info("Enforcing: {}", entrySet.getKey());
114         }
115
116         TopicEndpointManager.getManager().start();
117
118         @SuppressWarnings("resource") // never close System.in
119         var input = new Scanner(System.in);
120         while (!Thread.currentThread().isInterrupted()) {
121             String quit = input.nextLine();
122             if ("q".equalsIgnoreCase(quit)) {
123                 logger.info("quiting");
124                 break;
125             }
126         }
127
128         TopicEndpointManager.getManager().shutdown();
129
130     }
131
132     /**
133      * This method is called when a topic event is received.
134      */
135     @Override
136     public void onTopicEvent(CommInfrastructure infra, String topic, String event) {
137         logger.info("onTopicEvent {}", event);
138         if (scanForPolicyType(event)) {
139             Map<String, Object> newPolicies = getDecision(client, this.decisionRequest);
140             if (newPolicies.isEmpty()) {
141                 logger.info("Not enforcing any policies");
142             }
143             for (Entry<String, Object> entrySet : newPolicies.entrySet()) {
144                 logger.info("Now Enforcing: {}", entrySet.getKey());
145             }
146         }
147     }
148
149     /**
150      * Helper method that parses a DMaap message event for POLICY-NOTIFICATION
151      * looking for our supported policy type to enforce.
152      *
153      * @param msg Dmaap Message
154      * @return true if MY_POLICYTYPEID is in the message
155      */
156     private boolean scanForPolicyType(String msg) {
157         var gson = new StandardCoder();
158         try {
159             PolicyNotification notification = gson.decode(msg, PolicyNotification.class);
160             for (PolicyStatus added : notification.getAdded()) {
161                 if (MY_POLICYTYPEID.equals(added.getPolicyTypeId())) {
162                     return true;
163                 }
164             }
165             for (PolicyStatus deleted : notification.getDeleted()) {
166                 if (MY_POLICYTYPEID.equals(deleted.getPolicyTypeId())) {
167                     return true;
168                 }
169             }
170         } catch (CoderException e) {
171             logger.error("StandardCoder failed to parse PolicyNotification", e);
172         }
173         return false;
174     }
175
176
177     /**
178      * Helper method that calls the XACML PDP Decision API to get a Decision
179      * as to which policy we should be enforcing.
180      *
181      * @param client HttpClient to use to make REST call
182      * @param decisionRequest DecisionRequest object to send
183      * @return The Map of policies that was in the DecisionResponse object
184      */
185     private Map<String, Object> getDecision(HttpClient client, DecisionRequest decisionRequest) {
186         decisionRequest.setRequestId(requestId.toString());
187         requestId++;
188
189         Entity<DecisionRequest> entityRequest =
190                 Entity.entity(decisionRequest, MediaType.APPLICATION_JSON);
191         var response = client.post("/decision", entityRequest, Collections.emptyMap());
192
193         if (response.getStatus() != 200) {
194             logger.error(
195                     "Decision API failed - is the IP/port correct? {}", response.getStatus());
196             return Collections.emptyMap();
197         }
198
199         var decisionResponse = HttpClient.getBody(response, DecisionResponse.class);
200
201         return decisionResponse.getPolicies();
202     }
203
204     /**
205      * Our Main application entry point.
206      *
207      * @param args command line arguments
208      */
209     public static void main(String[] args) {
210         logger.info("Hello Welcome to ONAP Enforcement Tutorial!");
211
212         var app = new App(args);
213
214         app.start();
215
216         try {
217             app.join();
218         } catch (InterruptedException e) {
219             Thread.currentThread().interrupt();
220             logger.warn("Thread interrupted");
221         }
222
223         logger.info("Tutorial ended");
224     }
225
226 }