CHeckstyle and JUnit for base package in ONAP-REST
[policy/engine.git] / ONAP-PDP-REST / src / main / java / org / onap / policy / pdp / rest / notifications / NotificationController.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP-PDP-REST
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.pdp.rest.notifications;
22
23 import java.io.File;
24 import java.io.FileFilter;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.OutputStream;
29 import java.net.URL;
30 import java.net.URLConnection;
31 import java.nio.file.Files;
32 import java.nio.file.Path;
33 import java.nio.file.Paths;
34 import java.util.HashMap;
35 import java.util.HashSet;
36 import java.util.Iterator;
37 import java.util.Map;
38
39 import org.apache.commons.io.IOUtils;
40 import org.apache.commons.io.filefilter.WildcardFileFilter;
41 import org.onap.policy.api.NotificationType;
42 import org.onap.policy.api.RemovedPolicy;
43 import org.onap.policy.api.UpdateType;
44 import org.onap.policy.common.logging.flexlogger.FlexLogger;
45 import org.onap.policy.common.logging.flexlogger.Logger;
46 import org.onap.policy.pdp.rest.PapUrlResolver;
47 import org.onap.policy.rest.XacmlRestProperties;
48 import org.onap.policy.xacml.api.XACMLErrorConstants;
49
50 import com.att.research.xacml.api.pap.PDPPolicy;
51 import com.att.research.xacml.api.pap.PDPStatus;
52 import com.att.research.xacml.util.XACMLProperties;
53 import com.att.research.xacmlatt.pdp.policy.AllOf;
54 import com.att.research.xacmlatt.pdp.policy.AnyOf;
55 import com.att.research.xacmlatt.pdp.policy.Match;
56 import com.att.research.xacmlatt.pdp.policy.PolicyDef;
57 import com.fasterxml.jackson.core.JsonProcessingException;
58 import com.fasterxml.jackson.databind.ObjectMapper;
59 import com.fasterxml.jackson.databind.ObjectWriter;
60
61 /**
62  * NotificationController Checks for the Updated and Removed policies. It notifies the Server to send Notifications to
63  * the Client.
64  *
65  * @version 0.2
66  *
67  */
68 public class NotificationController {
69     private static final Logger LOGGER = FlexLogger.getLogger(NotificationController.class);
70     private static Notification record = new Notification();
71     private PDPStatus oldStatus = null;
72     private Removed removed = null;
73     private Updated updated = null;
74     private ManualNotificationUpdateThread registerMaunualNotificationRunnable = null;
75     private Thread manualNotificationThread = null;
76     private boolean manualThreadStarted = false;
77
78     private static String notificationJSON = null;
79     private static String propNotificationType = null;
80     private static String pdpURL = null;
81     private static Boolean notificationFlag = false;
82
83     public void check(PDPStatus newStatus, Map<String, PolicyDef> policyContainer) {
84
85         LOGGER.info("NotificationController: checking for updated and removed policies.");
86         boolean isUpdated = false;
87         boolean isRemoved = false;
88         Notification notification = new Notification();
89         HashSet<Removed> removedPolicies = new HashSet<>();
90         HashSet<Updated> updatedPolicies = new HashSet<>();
91
92         if (oldStatus == null) {
93             oldStatus = newStatus;
94         }
95
96         LOGGER.info("old config Status :" + oldStatus.getStatus());
97         LOGGER.info("new config Status :" + newStatus.getStatus());
98
99         // Depending on the above condition taking the Change as an Update.
100         if (oldStatus.getStatus().toString() != newStatus.getStatus().toString()) {
101             LOGGER.info("There is an Update to the PDP");
102             LOGGER.debug(oldStatus.getLoadedPolicies());
103             LOGGER.debug(newStatus.getLoadedPolicies());
104
105             // Check if there is an Update/additions in the policy.
106                 LOGGER.info("NotificationController: check for updated or new policies");
107             for (PDPPolicy newPolicy : newStatus.getLoadedPolicies()) {
108                 boolean change = true;
109                 for (PDPPolicy oldPolicy : oldStatus.getLoadedPolicies()) {
110                     // Check if there are same policies.
111                     if (oldPolicy.getId().equals(newPolicy.getId())) {
112                         // Check if they have same version.
113                         if (oldPolicy.getVersion().equals(newPolicy.getVersion())) {
114                             change = false;
115                         }
116                     }
117                 }
118                 // if there is a change Send the notifications to the Client.
119                 if (change) {
120                         LOGGER.info("NotificationController: sending update/new policy notification");
121                     sendUpdate(newPolicy, policyContainer);
122                     isUpdated = true;
123                     updatedPolicies.add(this.updated);
124                 }
125             }
126             // Check if there is any removal of policy.
127                 LOGGER.info("NotificationController: check for removed policies");
128             for (PDPPolicy oldPolicy : oldStatus.getLoadedPolicies()) {
129                 boolean change = true;
130                 for (PDPPolicy newPolicy : newStatus.getLoadedPolicies()) {
131                     // Check if there are same policies.
132                     if (oldPolicy.getId().equals(newPolicy.getId())) {
133                         // Check if they have same version.
134                         if (oldPolicy.getVersion().equals(newPolicy.getVersion())) {
135                             change = false;
136                         }
137                     }
138                 }
139                 // if there is a change Send the notifications to the Client.
140                 if (change) {
141                         LOGGER.info("NotificationController: sending removal notification");
142                     sendremove(oldPolicy);
143                     isRemoved = true;
144                     removedPolicies.add(this.removed);
145                 }
146             }
147         }
148         // At the end the oldStatus must be updated with the newStatus.
149         oldStatus = newStatus;
150         // Sending Notification to the Server to pass over to the clients
151         if (isUpdated || isRemoved) {
152             // Call the Notification Server..
153             notification.setRemovedPolicies(removedPolicies);
154             notification.setLoadedPolicies(updatedPolicies);
155             notification = setUpdateTypes(isUpdated, isRemoved, notification);
156             ObjectWriter om = new ObjectMapper().writer();
157             try {
158                 setNotificationJSON(om.writeValueAsString(notification));
159                 LOGGER.info("NotificationController notificationJson: " + notificationJSON);
160                 // NotificationServer Method here.
161                 setPropNotification();
162                 if (("ueb".equals(propNotificationType) || "dmaap".equals(propNotificationType))
163                         && !manualThreadStarted) {
164                     LOGGER.debug("Starting  Thread to accept UEB or DMAAP notfications.");
165                     this.registerMaunualNotificationRunnable = new ManualNotificationUpdateThread();
166                     this.manualNotificationThread = new Thread(this.registerMaunualNotificationRunnable);
167                     this.manualNotificationThread.start();
168                     manualThreadStarted = true;
169                 }
170                 String notificationJSONString = null;
171                 setNotificationFlag(true);
172                 try {
173                     notificationJSONString = record(notification);
174                 } catch (Exception e) {
175                     LOGGER.error(e);
176                 }
177                 NotificationServer.setUpdate(notificationJSONString);
178                 ManualNotificationUpdateThread.setUpdate(notificationJSONString);
179             } catch (JsonProcessingException e) {
180                 LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e.getMessage() + e);
181             }
182         }
183     }
184
185     private static void setNotificationFlag(boolean value) {
186         notificationFlag = value;
187     }
188
189     private static void setNotificationJSON(String message) {
190         notificationJSON = message;
191     }
192
193     private static void setPropNotification() {
194         propNotificationType = XACMLProperties.getProperty(XacmlRestProperties.PROP_NOTIFICATION_TYPE);
195         pdpURL = XACMLProperties.getProperty(XacmlRestProperties.PROP_PDP_ID);
196     }
197
198     public static void sendNotification() {
199         if (notificationFlag) {
200             try {
201                         LOGGER.info("NotificationController: calling NotificationServer to sendNotification");
202                 NotificationServer.sendNotification(notificationJSON, propNotificationType, pdpURL);
203             } catch (Exception e) {
204                 LOGGER.info(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Error in sending the Event Notification: "
205                         + e.getMessage() + e);
206             }
207             notificationFlag = false;
208         }
209     }
210
211     private void sendremove(PDPPolicy oldPolicy) {
212         removed = new Removed();
213         // Want to know what is removed ?
214         LOGGER.info("Policy removed: " + oldPolicy.getId() + " with version number: " + oldPolicy.getVersion());
215         removed.setPolicyName(oldPolicy.getId());
216         removed.setVersionNo(oldPolicy.getVersion());
217         removeFile(oldPolicy);
218     }
219
220     private void sendUpdate(PDPPolicy newPolicy, Map<String, PolicyDef> policyContainer) {
221         updated = new Updated();
222         // Want to know what is new ?
223         LOGGER.info("The new Policy is: " + newPolicy.getId());
224         LOGGER.info("The version no. is: " + newPolicy.getVersion());
225         updated.setPolicyName(newPolicy.getId());
226         updated.setVersionNo(newPolicy.getVersion());
227         updated.setUpdateType(UpdateType.NEW);
228         // If the policy is of Config type then retrieve its matches.
229         if (newPolicy.getName().contains(".Config_")) {
230             // Take a Configuration copy to PDP webapps.
231             final String urlStart = "attributeId=URLID,expression";
232             final String urlEnd = "}}},{";
233             String policy = policyContainer.get(newPolicy.getId()).toString();
234             if (policy.contains(urlStart)) {
235                 String urlFinePartOne = policy.substring(policy.indexOf(urlStart) + urlStart.length());
236                 String urlFinePart = urlFinePartOne.substring(0, urlFinePartOne.indexOf(urlEnd));
237                 String urlString = urlFinePart.substring(urlFinePart.indexOf("value=$URL") + 6);
238                 callPap(urlString, "Config");
239             }
240             Iterator<AnyOf> anyOfs = policyContainer.get(newPolicy.getId()).getTarget().getAnyOfs();
241             while (anyOfs.hasNext()) {
242                 AnyOf anyOf = anyOfs.next();
243                 Iterator<AllOf> allOfs = anyOf.getAllOfs();
244                 while (allOfs.hasNext()) {
245                     AllOf allOf = allOfs.next();
246                     Iterator<Match> matches = allOf.getMatches();
247                     HashMap<String, String> matchValues = new HashMap<>();
248                     while (matches.hasNext()) {
249                         Match match = matches.next();
250                         LOGGER.info("Attribute Value is: " + match.getAttributeValue().getValue().toString());
251                         String[] result = match.getAttributeRetrievalBase().toString().split("attributeId=");
252                         result[1] = result[1].replaceAll("}", "");
253                         if (!result[1].equals("urn:oasis:names:tc:xacml:1.0:subject:subject-id")) {
254                             LOGGER.info("Attribute id is: " + result[1]);
255                         }
256                         matchValues.put(result[1], match.getAttributeValue().getValue().toString());
257                         LOGGER.info(
258                                 "Match is : " + result[1] + " , " + match.getAttributeValue().getValue().toString());
259                     }
260                     updated.setMatches(matchValues);
261                 }
262             }
263         } else if (newPolicy.getName().contains(".Action_")) {
264             // Take Configuration copy to PDP Webapps.
265             // Action policies have .json as extension.
266             String urlString = "$URL/Action/" + newPolicy.getId().substring(0, newPolicy.getId().lastIndexOf('.'))
267                     + ".json";
268             callPap(urlString, "Action");
269         }
270     }
271
272     // Adding this for Recording the changes to serve Polling requests..
273     private static String record(Notification notification) {
274         // Initialization with updates.
275         if (record.getRemovedPolicies() == null || record.getLoadedPolicies() == null) {
276             record.setRemovedPolicies(notification.getRemovedPolicies());
277             record.setLoadedPolicies(notification.getLoadedPolicies());
278         } else {
279             // Check if there is anything new and update the record..
280             if (record.getLoadedPolicies() != null || record.getRemovedPolicies() != null) {
281                 HashSet<Removed> removedPolicies = (HashSet<Removed>) record.getRemovedPolicies();
282                 HashSet<Updated> updatedPolicies = (HashSet<Updated>) record.getLoadedPolicies();
283
284                 // Checking with New updated policies.
285                 if (notification.getLoadedPolicies() != null && !notification.getLoadedPolicies().isEmpty()) {
286                     for (Updated newUpdatedPolicy : notification.getLoadedPolicies()) {
287                         // If it was removed earlier then we need to remove from our record
288                         Iterator<Removed> oldRemovedPolicy = removedPolicies.iterator();
289                         while (oldRemovedPolicy.hasNext()) {
290                             Removed policy = oldRemovedPolicy.next();
291                             if (newUpdatedPolicy.getPolicyName().equals(policy.getPolicyName())) {
292                                 if (newUpdatedPolicy.getVersionNo().equals(policy.getVersionNo())) {
293                                     oldRemovedPolicy.remove();
294                                 }
295                             }
296                         }
297                         // If it was previously updated need to Overwrite it to the record.
298                         Iterator<Updated> oldUpdatedPolicy = updatedPolicies.iterator();
299                         while (oldUpdatedPolicy.hasNext()) {
300                             Updated policy = oldUpdatedPolicy.next();
301                             if (newUpdatedPolicy.getPolicyName().equals(policy.getPolicyName())) {
302                                 if (newUpdatedPolicy.getVersionNo().equals(policy.getVersionNo())) {
303                                     oldUpdatedPolicy.remove();
304                                 }
305                             }
306                         }
307                         updatedPolicies.add(newUpdatedPolicy);
308                     }
309                 }
310                 // Checking with New Removed policies.
311                 if (notification.getRemovedPolicies() != null && !notification.getRemovedPolicies().isEmpty()) {
312                     for (Removed newRemovedPolicy : notification.getRemovedPolicies()) {
313                         // If it was previously removed Overwrite it to the record.
314                         Iterator<Removed> oldRemovedPolicy = removedPolicies.iterator();
315                         while (oldRemovedPolicy.hasNext()) {
316                             Removed policy = oldRemovedPolicy.next();
317                             if (newRemovedPolicy.getPolicyName().equals(policy.getPolicyName())) {
318                                 if (newRemovedPolicy.getVersionNo().equals(policy.getVersionNo())) {
319                                     oldRemovedPolicy.remove();
320                                 }
321                             }
322                         }
323                         // If it was added earlier then we need to remove from our record.
324                         Iterator<Updated> oldUpdatedPolicy = updatedPolicies.iterator();
325                         while (oldUpdatedPolicy.hasNext()) {
326                             Updated policy = oldUpdatedPolicy.next();
327                             if (newRemovedPolicy.getPolicyName().equals(policy.getPolicyName())) {
328                                 if (newRemovedPolicy.getVersionNo().equals(policy.getVersionNo())) {
329                                     oldUpdatedPolicy.remove();
330                                 }
331                             }
332                         }
333                         removedPolicies.add(newRemovedPolicy);
334                     }
335                 }
336                 record.setRemovedPolicies(removedPolicies);
337                 record.setLoadedPolicies(updatedPolicies);
338             }
339         }
340         // Send the Result to the caller.
341         ObjectWriter om = new ObjectMapper().writer();
342         String json = null;
343         try {
344             json = om.writeValueAsString(record);
345         } catch (JsonProcessingException e) {
346             LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e.getMessage() + e);
347         }
348         LOGGER.info(json);
349         return json;
350     }
351
352     private static Notification setUpdateTypes(boolean updated, boolean removed, Notification notification) {
353         if (notification != null) {
354             if (updated && removed) {
355                 notification.setNotificationType(NotificationType.BOTH);
356                 if (notification.getLoadedPolicies() != null) {
357                     HashSet<Updated> updatedPolicies = new HashSet<>();
358                     for (Updated oldUpdatedPolicy : notification.getLoadedPolicies()) {
359                         Updated updatePolicy = oldUpdatedPolicy;
360                         if (notification.getRemovedPolicies() != null) {
361                             for (RemovedPolicy removedPolicy : notification.getRemovedPolicies()) {
362                                 String regex = ".(\\d)*.xml";
363                                 if (removedPolicy.getPolicyName().replaceAll(regex, "")
364                                         .equals(oldUpdatedPolicy.getPolicyName().replaceAll(regex, ""))) {
365                                     updatePolicy.setUpdateType(UpdateType.UPDATE);
366                                     break;
367                                 }
368                             }
369                         }
370                         updatedPolicies.add(updatePolicy);
371                     }
372                     notification.setLoadedPolicies(updatedPolicies);
373                 }
374             } else if (updated) {
375                 notification.setNotificationType(NotificationType.UPDATE);
376             } else if (removed) {
377                 notification.setNotificationType(NotificationType.REMOVE);
378             }
379         }
380         return notification;
381     }
382
383     private void removeFile(PDPPolicy oldPolicy) {
384         try {
385             Path removedPolicyFile = Paths.get(XACMLProperties.getProperty(XacmlRestProperties.PROP_PDP_CONFIG)
386                     + File.separator + oldPolicy.getId());
387             Files.deleteIfExists(removedPolicyFile);
388             boolean delete = false;
389             File dir = null;
390             if (oldPolicy.getName().contains(".Config_")) {
391                 delete = true;
392                 dir = new File(
393                         XACMLProperties.getProperty(XacmlRestProperties.PROP_PDP_WEBAPPS) + File.separator + "Config");
394             } else if (oldPolicy.getName().contains(".Action_")) {
395                 delete = true;
396                 dir = new File(
397                         XACMLProperties.getProperty(XacmlRestProperties.PROP_PDP_WEBAPPS) + File.separator + "Action");
398             }
399             if (delete) {
400                 FileFilter fileFilter = new WildcardFileFilter(
401                         oldPolicy.getId().substring(0, oldPolicy.getId().lastIndexOf('.')) + ".*");
402                 File[] configFile = dir.listFiles(fileFilter);
403                 if (configFile.length == 1) {
404                     Files.deleteIfExists(configFile[0].toPath());
405                 }
406             }
407         } catch (Exception e) {
408             LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Couldn't remove the policy/config file "
409                     + oldPolicy.getName() + e);
410         }
411     }
412
413     private void callPap(String urlString, String type) {
414         Path configLocation = Paths
415                 .get(XACMLProperties.getProperty(XacmlRestProperties.PROP_PDP_WEBAPPS) + File.separator + type);
416         if (Files.notExists(configLocation)) {
417             try {
418                 Files.createDirectories(configLocation);
419             } catch (IOException e) {
420                 LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Failed to create config directory: "
421                         + configLocation.toAbsolutePath().toString(), e);
422             }
423         }
424         PapUrlResolver papUrls = PapUrlResolver.getInstance();
425         while (papUrls.hasMoreUrls()) {
426             String papPath = papUrls.getUrl();
427             papPath = papPath.substring(0, papPath.lastIndexOf("/pap"));
428             String papAddress = urlString.replace("$URL", papPath);
429             String fileName = papAddress.substring(papAddress.lastIndexOf('/') + 1);
430             String fileLocation = configLocation.toString() + File.separator + fileName;
431             try {
432                 URL papURL = new URL(papAddress);
433                 LOGGER.info("Calling " + papAddress + " for Configuration Copy.");
434                 URLConnection urlConnection = papURL.openConnection();
435                 File file = new File(fileLocation);
436                 try (InputStream is = urlConnection.getInputStream(); OutputStream os = new FileOutputStream(file)) {
437                     IOUtils.copy(is, os);
438                     break;
439                 }
440             } catch (Exception e) {
441                 LOGGER.error(e + e.getMessage());
442             }
443             papUrls.getNext();
444         }
445     }
446 }