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