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