[POLICY-117] Resolve the Policy Critical issues
[policy/engine.git] / ECOMP-PDP-REST / src / main / java / org / openecomp / policy / pdp / rest / notifications / NotificationController.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ECOMP-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.openecomp.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.openecomp.policy.api.NotificationType;
42 import org.openecomp.policy.api.RemovedPolicy;
43 import org.openecomp.policy.api.UpdateType;
44 import org.openecomp.policy.common.logging.flexlogger.FlexLogger;
45 import org.openecomp.policy.common.logging.flexlogger.Logger;
46 import org.openecomp.policy.pdp.rest.PapUrlResolver;
47 import org.openecomp.policy.rest.XACMLRestProperties;
48 import org.openecomp.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
63  * notifies the Server to send Notifications to 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                                 notificationJSON = om.writeValueAsString(notification);
152                                 LOGGER.info(notificationJSON);
153                                 // NotificationServer Method here.
154                                 propNotificationType = XACMLProperties.getProperty(XACMLRestProperties.PROP_NOTIFICATION_TYPE);
155                                 pdpURL = XACMLProperties.getProperty(XACMLRestProperties.PROP_PDP_ID);
156                                 if (("ueb".equals(propNotificationType)||"dmaap".equals(propNotificationType)) && !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 notificationJSON= null;
164                                 notificationFlag = true;
165                                 try{
166                                         notificationJSON= record(notification);
167                                 }catch(Exception e){
168                                         LOGGER.error(e);
169                                 }
170                                 NotificationServer.setUpdate(notificationJSON);
171                                 ManualNotificationUpdateThread.setUpdate(notificationJSON);
172                         } catch (JsonProcessingException e) {
173                                 LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e.getMessage() +e);
174                         }
175                 }
176         }
177         
178         public static void sendNotification(){
179                 if(notificationFlag){
180                         try {
181                                 NotificationServer.sendNotification(notificationJSON, propNotificationType, pdpURL);
182                         } catch (Exception e) {
183                                 LOGGER.info(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Error in sending the Event Notification: "+ e.getMessage() + e);
184                         }
185                         notificationFlag = false;
186                 }
187         }
188         
189         private void sendremove(PDPPolicy oldPolicy) {
190                 removed = new Removed();
191                 // Want to know what is removed ?
192                 LOGGER.info("Policy removed: " + oldPolicy.getId()+ " with version number: " + oldPolicy.getVersion());
193                 removed.setPolicyName(oldPolicy.getId());
194                 removed.setVersionNo(oldPolicy.getVersion());
195                 removeFile(oldPolicy);
196         }
197
198         private void sendUpdate(PDPPolicy newPolicy,Map<String, PolicyDef> policyContainer) {
199                 updated = new Updated();
200                 // Want to know what is new ?
201                 LOGGER.info("The new Policy is: " + newPolicy.getId());
202                 LOGGER.info("The version no. is: " + newPolicy.getVersion());
203                 updated.setPolicyName(newPolicy.getId());
204                 updated.setVersionNo(newPolicy.getVersion());
205                 updated.setUpdateType(UpdateType.NEW);
206                 // If the policy is of Config type then retrieve its matches.
207                 if (newPolicy.getName().contains(".Config_")) {
208                         // Take a Configuration copy to PDP webapps. 
209                         final String urlStart = "attributeId=URLID,expression";
210                         final String urlEnd = "}}},{";
211                         String policy = policyContainer.get(newPolicy.getId()).toString(); 
212                         if(policy.contains(urlStart)){
213                                 String urlFinePartOne = policy.substring(policy.indexOf(urlStart)+urlStart.length());
214                                 String urlFinePart = urlFinePartOne.substring(0,urlFinePartOne.indexOf(urlEnd));
215                                 String urlString = urlFinePart.substring(urlFinePart.indexOf("value=$URL")+6); 
216                                 callPap(urlString, "Config");
217                         }
218                         Iterator<AnyOf> anyOfs = policyContainer.get(newPolicy.getId()).getTarget().getAnyOfs();
219                         while (anyOfs.hasNext()) {
220                                 AnyOf anyOf = anyOfs.next();
221                                 Iterator<AllOf> allOfs = anyOf.getAllOfs();
222                                 while (allOfs.hasNext()) {
223                                         AllOf allOf = allOfs.next();
224                                         Iterator<Match> matches = allOf.getMatches();
225                                         HashMap<String, String> matchValues = new HashMap<>();
226                                         while (matches.hasNext()) {
227                                                 Match match = matches.next();
228                                                 LOGGER.info("Attribute Value is: "+ match.getAttributeValue().getValue().toString());
229                                                 String[] result = match.getAttributeRetrievalBase().toString().split("attributeId=");
230                                                 result[1] = result[1].replaceAll("}", "");
231                                                 if (!result[1].equals("urn:oasis:names:tc:xacml:1.0:subject:subject-id")) {
232                                                         LOGGER.info("Attribute id is: " + result[1]);
233                                                 }
234                                                 matchValues.put(result[1], match.getAttributeValue().getValue().toString());
235                                                 LOGGER.info("Match is : "+ result[1]+ " , "     + match.getAttributeValue().getValue().toString());
236                                         }
237                                         updated.setMatches(matchValues);
238                                 }
239                         }
240                 }else if(newPolicy.getName().contains(".Action_")){
241                         // Take Configuration copy to PDP Webapps.
242                         // Action policies have .json as extension. 
243                         String urlString = "$URL/Action/" + newPolicy.getId().substring(0, newPolicy.getId().lastIndexOf(".")) + ".json";
244                         callPap(urlString, "Action");
245                 }
246         }
247
248         // Adding this for Recording the changes to serve Polling requests..
249         private static String record(Notification notification) throws Exception {
250                 // Initialization with updates.
251                 if (record.getRemovedPolicies() == null || record.getLoadedPolicies() == null) {
252                         record.setRemovedPolicies(notification.getRemovedPolicies());
253                         record.setLoadedPolicies(notification.getLoadedPolicies());
254                 } else {
255                         // Check if there is anything new and update the record..
256                         if (record.getLoadedPolicies() != null  || record.getRemovedPolicies() != null) {
257                                 HashSet<Removed> removedPolicies = (HashSet<Removed>) record.getRemovedPolicies();
258                                 HashSet<Updated> updatedPolicies = (HashSet<Updated>) record.getLoadedPolicies();
259
260                                 // Checking with New updated policies.
261                                 if (notification.getLoadedPolicies() != null && !notification.getLoadedPolicies().isEmpty()) {
262                                         for (Updated newUpdatedPolicy : notification.getLoadedPolicies()) {
263                                                 // If it was removed earlier then we need to remove from our record
264                                                 Iterator<Removed> oldRemovedPolicy = removedPolicies.iterator();
265                                                 while (oldRemovedPolicy.hasNext()) {
266                                                         Removed policy = oldRemovedPolicy.next();
267                                                         if (newUpdatedPolicy.getPolicyName().equals(policy.getPolicyName())) {
268                                                                 if (newUpdatedPolicy.getVersionNo().equals(policy.getVersionNo())) {
269                                                                         oldRemovedPolicy.remove();
270                                                                 }
271                                                         }
272                                                 }
273                                                 // If it was previously updated need to Overwrite it to the record.
274                                                 Iterator<Updated> oldUpdatedPolicy = updatedPolicies.iterator();
275                                                 while (oldUpdatedPolicy.hasNext()) {
276                                                         Updated policy = oldUpdatedPolicy.next();
277                                                         if (newUpdatedPolicy.getPolicyName().equals(policy.getPolicyName())) {
278                                                                 if (newUpdatedPolicy.getVersionNo().equals(policy.getVersionNo())) {
279                                                                         oldUpdatedPolicy.remove();
280                                                                 }
281                                                         }
282                                                 }
283                                                 updatedPolicies.add(newUpdatedPolicy);
284                                         }
285                                 }
286                                 // Checking with New Removed policies.
287                                 if (notification.getRemovedPolicies() != null && !notification.getRemovedPolicies().isEmpty()) {
288                                         for (Removed newRemovedPolicy : notification.getRemovedPolicies()) {
289                                                 // If it was previously removed Overwrite it to the record.
290                                                 Iterator<Removed> oldRemovedPolicy = removedPolicies.iterator();
291                                                 while (oldRemovedPolicy.hasNext()) {
292                                                         Removed policy = oldRemovedPolicy.next();
293                                                         if (newRemovedPolicy.getPolicyName().equals(policy.getPolicyName())) {
294                                                                 if (newRemovedPolicy.getVersionNo().equals(policy.getVersionNo())) {
295                                                                         oldRemovedPolicy.remove();
296                                                                 }
297                                                         }
298                                                 }
299                                                 // If it was added earlier then we need to remove from our record.
300                                                 Iterator<Updated> oldUpdatedPolicy = updatedPolicies.iterator();
301                                                 while (oldUpdatedPolicy.hasNext()) {
302                                                         Updated policy = oldUpdatedPolicy.next();
303                                                         if (newRemovedPolicy.getPolicyName().equals(policy.getPolicyName())) {
304                                                                 if (newRemovedPolicy.getVersionNo().equals(policy.getVersionNo())) {
305                                                                         oldUpdatedPolicy.remove();
306                                                                 }
307                                                         }
308                                                 }
309                                                 removedPolicies.add(newRemovedPolicy);
310                                         }
311                                 }
312                                 record.setRemovedPolicies(removedPolicies);
313                                 record.setLoadedPolicies(updatedPolicies);
314                         }
315                 }
316                 // Send the Result to the caller.
317                 ObjectWriter om = new ObjectMapper().writer();
318                 String json = null;
319                 try {
320                         json = om.writeValueAsString(record);
321                 } catch (JsonProcessingException e) {
322                         LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e.getMessage() + e);
323                 }
324                 LOGGER.info(json);
325                 return json;
326         }
327         
328         private static Notification setUpdateTypes(boolean updated, boolean removed, Notification notification) {
329         if(notification!=null){
330             if(updated && removed){
331                 notification.setNotificationType(NotificationType.BOTH);
332                 if(notification.getLoadedPolicies()!=null){
333                     HashSet<Updated> updatedPolicies = new HashSet<>(); 
334                     for(Updated oldUpdatedPolicy: notification.getLoadedPolicies()){
335                         Updated updatePolicy = oldUpdatedPolicy;
336                         if(notification.getRemovedPolicies()!=null){
337                             for(RemovedPolicy removedPolicy: notification.getRemovedPolicies()){
338                                 String regex = ".(\\d)*.xml";
339                                 if(removedPolicy.getPolicyName().replaceAll(regex, "").equals(oldUpdatedPolicy.getPolicyName().replaceAll(regex, ""))){
340                                     updatePolicy.setUpdateType(UpdateType.UPDATE);
341                                     break;
342                                 }
343                             }
344                         }
345                         updatedPolicies.add(updatePolicy);
346                     }
347                     notification.setLoadedPolicies(updatedPolicies);
348                 }
349             }else if(updated){
350                 notification.setNotificationType(NotificationType.UPDATE);
351             }else if(removed){
352                 notification.setNotificationType(NotificationType.REMOVE);
353             }
354         }
355         return notification;
356     }
357         
358         private void removeFile(PDPPolicy oldPolicy) {
359                 try{
360                         Path removedPolicyFile = Paths.get(XACMLProperties.getProperty(XACMLRestProperties.PROP_PDP_CONFIG)+File.separator+oldPolicy.getId());
361                         Files.deleteIfExists(removedPolicyFile);
362                         boolean delete=false;
363                         File dir= null;
364                         if(oldPolicy.getName().startsWith("Config")){
365                                 delete = true;
366                                 dir = new File(XACMLProperties.getProperty(XACMLRestProperties.PROP_PDP_WEBAPPS)+File.separator+"Config");
367                         }else if(oldPolicy.getName().startsWith("Action")){
368                                 delete = true;
369                                 dir = new File(XACMLProperties.getProperty(XACMLRestProperties.PROP_PDP_WEBAPPS)+File.separator+"Action");
370                         }
371                         if(delete){
372                                 FileFilter fileFilter = new WildcardFileFilter(oldPolicy.getId().substring(0, oldPolicy.getId().lastIndexOf("."))+".*");
373                                 File[] configFile = dir.listFiles(fileFilter);
374                                 if(configFile.length==1){
375                                         Files.deleteIfExists(configFile[0].toPath());
376                                 }
377                         }
378                 }catch(Exception e){
379                         LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Couldn't remove the policy/config file " + oldPolicy.getName() + e);
380                 }
381         }
382         
383         private void callPap(String urlString, String type) {
384                 Path configLocation = Paths.get(XACMLProperties.getProperty(XACMLRestProperties.PROP_PDP_WEBAPPS)+File.separator+type);
385                 if(Files.notExists(configLocation)){
386                         try {
387                                 Files.createDirectories(configLocation);
388                         } catch (IOException e) {
389                                 LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW +"Failed to create config directory: " + configLocation.toAbsolutePath().toString(), e);
390                         }
391                 }
392                 PapUrlResolver papUrls = PapUrlResolver.getInstance();
393                 while(papUrls.hasMoreUrls()){
394                         String papPath = papUrls.getUrl();
395                         papPath = papPath.substring(0, papPath.lastIndexOf("/pap"));
396                         String papAddress= urlString.replace("$URL", papPath);
397                         String fileName = papAddress.substring(papAddress.lastIndexOf("/")+1);
398                         String fileLocation = configLocation.toString() + File.separator + fileName;
399                         try {
400                                 URL papURL = new URL(papAddress);
401                                 LOGGER.info("Calling " +papAddress + " for Configuration Copy.");
402                                 URLConnection urlConnection = papURL.openConnection();
403                                 File file= new File(fileLocation);
404                                 try (InputStream is = urlConnection.getInputStream();
405                                                 OutputStream os = new FileOutputStream(file)) {
406                                         IOUtils.copy(is, os);
407                                         break;
408                                 }
409                         } catch (Exception e) {
410                                 LOGGER.error(e + e.getMessage());
411                         }
412                         papUrls.getNext();
413                 }
414         }
415 }