2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.openecomp.policy.pdp.rest.notifications;
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;
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;
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;
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;
64 * NotificationController Checks for the Updated and Removed policies. It
65 * notifies the Server to send Notifications to the Client.
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;
80 private static String notificationJSON = null;
81 private static String propNotificationType = null;
82 private static String pdpURL = null;
83 private static Boolean notificationFlag = false;
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<>();
92 if (oldStatus == null) {
93 oldStatus = newStatus;
95 // Debugging purpose only.
96 LOGGER.debug("old config Status :" + oldStatus.getStatus());
97 LOGGER.debug("new config Status :" + newStatus.getStatus());
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())) {
116 // if there is a change Send the notifications to the Client.
118 sendUpdate(newPolicy, policyContainer);
120 updatedPolicies.add(this.updated);
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())) {
135 // if there is a change Send the notifications to the Client.
137 sendremove(oldPolicy);
139 removedPolicies.add(this.removed);
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();
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;
165 String notificationJSON= null;
166 notificationFlag = true;
168 notificationJSON= record(notification);
172 NotificationServer.setUpdate(notificationJSON);
173 ManualNotificationUpdateThread.setUpdate(notificationJSON);
174 } catch (JsonProcessingException e) {
175 LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e.getMessage());
180 public static void sendNotification(){
181 if(notificationFlag){
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());
187 notificationFlag = false;
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);
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");
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]);
236 matchValues.put(result[1], match.getAttributeValue().getValue().toString());
237 LOGGER.info("Match is : "+ result[1]+ " , " + match.getAttributeValue().getValue().toString());
239 updated.setMatches(matchValues);
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");
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());
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();
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();
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();
285 updatedPolicies.add(newUpdatedPolicy);
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();
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();
311 removedPolicies.add(newRemovedPolicy);
314 record.setRemovedPolicies(removedPolicies);
315 record.setLoadedPolicies(updatedPolicies);
318 // Send the Result to the caller.
319 ObjectWriter om = new ObjectMapper().writer();
322 json = om.writeValueAsString(record);
323 } catch (JsonProcessingException e) {
324 LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e.getMessage());
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);
347 updatedPolicies.add(updatePolicy);
349 notification.setLoadedPolicies(updatedPolicies);
352 notification.setNotificationType(NotificationType.UPDATE);
354 notification.setNotificationType(NotificationType.REMOVE);
360 private void removeFile(PDPPolicy oldPolicy) {
362 Path removedPolicyFile = Paths.get(XACMLProperties.getProperty(XACMLRestProperties.PROP_PDP_CONFIG)+File.separator+oldPolicy.getId());
363 Files.deleteIfExists(removedPolicyFile);
364 boolean delete=false;
366 if(oldPolicy.getName().startsWith("Config")){
368 dir = new File(XACMLProperties.getProperty(XACMLRestProperties.PROP_PDP_WEBAPPS)+File.separator+"Config");
369 }else if(oldPolicy.getName().startsWith("Action")){
371 dir = new File(XACMLProperties.getProperty(XACMLRestProperties.PROP_PDP_WEBAPPS)+File.separator+"Action");
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());
381 LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Couldn't remove the policy/config file " + oldPolicy.getName() + e);
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)){
389 Files.createDirectories(configLocation);
390 } catch (IOException e) {
391 LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW +"Failed to create config directory: " + configLocation.toAbsolutePath().toString(), e);
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;
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);
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());