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