2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2018 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.onap.policy.pdp.rest.notifications;
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;
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;
39 import org.apache.commons.io.IOUtils;
40 import org.apache.commons.io.filefilter.WildcardFileFilter;
41 import org.onap.policy.api.NotificationType;
42 import org.onap.policy.api.RemovedPolicy;
43 import org.onap.policy.api.UpdateType;
44 import org.onap.policy.common.logging.flexlogger.FlexLogger;
45 import org.onap.policy.common.logging.flexlogger.Logger;
46 import org.onap.policy.pdp.rest.PapUrlResolver;
47 import org.onap.policy.rest.XacmlRestProperties;
48 import org.onap.policy.xacml.api.XACMLErrorConstants;
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;
62 * NotificationController Checks for the Updated and Removed policies. It notifies the Server to send Notifications to
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;
78 private static String notificationJSON = null;
79 private static String propNotificationType = null;
80 private static String pdpURL = null;
81 private static Boolean notificationFlag = false;
83 public void check(PDPStatus newStatus, Map<String, PolicyDef> policyContainer) {
85 LOGGER.info("NotificationController: checking for updated and removed policies.");
86 boolean isUpdated = false;
87 boolean isRemoved = 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;
96 LOGGER.info("old config Status :" + oldStatus.getStatus());
97 LOGGER.info("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());
105 // Check if there is an Update/additions in the policy.
106 LOGGER.info("NotificationController: check for updated or new policies");
107 for (PDPPolicy newPolicy : newStatus.getLoadedPolicies()) {
108 boolean change = true;
109 for (PDPPolicy oldPolicy : oldStatus.getLoadedPolicies()) {
110 // Check if there are same policies.
111 if (oldPolicy.getId().equals(newPolicy.getId())) {
112 // Check if they have same version.
113 if (oldPolicy.getVersion().equals(newPolicy.getVersion())) {
118 // if there is a change Send the notifications to the Client.
120 LOGGER.info("NotificationController: sending update/new policy notification");
121 sendUpdate(newPolicy, policyContainer);
123 updatedPolicies.add(this.updated);
126 // Check if there is any removal of policy.
127 LOGGER.info("NotificationController: check for removed policies");
128 for (PDPPolicy oldPolicy : oldStatus.getLoadedPolicies()) {
129 boolean change = true;
130 for (PDPPolicy newPolicy : newStatus.getLoadedPolicies()) {
131 // Check if there are same policies.
132 if (oldPolicy.getId().equals(newPolicy.getId())) {
133 // Check if they have same version.
134 if (oldPolicy.getVersion().equals(newPolicy.getVersion())) {
139 // if there is a change Send the notifications to the Client.
141 LOGGER.info("NotificationController: sending removal notification");
142 sendremove(oldPolicy);
144 removedPolicies.add(this.removed);
148 // At the end the oldStatus must be updated with the newStatus.
149 oldStatus = newStatus;
150 // Sending Notification to the Server to pass over to the clients
151 if (isUpdated || isRemoved) {
152 // Call the Notification Server..
153 notification.setRemovedPolicies(removedPolicies);
154 notification.setLoadedPolicies(updatedPolicies);
155 notification = setUpdateTypes(isUpdated, isRemoved, notification);
156 ObjectWriter om = new ObjectMapper().writer();
158 setNotificationJSON(om.writeValueAsString(notification));
159 LOGGER.info("NotificationController notificationJson: " + notificationJSON);
160 // NotificationServer Method here.
161 setPropNotification();
162 if (("ueb".equals(propNotificationType) || "dmaap".equals(propNotificationType))
163 && !manualThreadStarted) {
164 LOGGER.debug("Starting Thread to accept UEB or DMAAP notfications.");
165 this.registerMaunualNotificationRunnable = new ManualNotificationUpdateThread();
166 this.manualNotificationThread = new Thread(this.registerMaunualNotificationRunnable);
167 this.manualNotificationThread.start();
168 manualThreadStarted = true;
170 String notificationJSONString = null;
171 setNotificationFlag(true);
173 notificationJSONString = record(notification);
174 } catch (Exception e) {
177 NotificationServer.setUpdate(notificationJSONString);
178 ManualNotificationUpdateThread.setUpdate(notificationJSONString);
179 } catch (JsonProcessingException e) {
180 LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e.getMessage() + e);
185 private static void setNotificationFlag(boolean value) {
186 notificationFlag = value;
189 private static void setNotificationJSON(String message) {
190 notificationJSON = message;
193 private static void setPropNotification() {
194 propNotificationType = XACMLProperties.getProperty(XacmlRestProperties.PROP_NOTIFICATION_TYPE);
195 pdpURL = XACMLProperties.getProperty(XacmlRestProperties.PROP_PDP_ID);
198 public static void sendNotification() {
199 if (notificationFlag) {
201 LOGGER.info("NotificationController: calling NotificationServer to sendNotification");
202 NotificationServer.sendNotification(notificationJSON, propNotificationType, pdpURL);
203 } catch (Exception e) {
204 LOGGER.info(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Error in sending the Event Notification: "
205 + e.getMessage() + e);
207 notificationFlag = false;
211 private void sendremove(PDPPolicy oldPolicy) {
212 removed = new Removed();
213 // Want to know what is removed ?
214 LOGGER.info("Policy removed: " + oldPolicy.getId() + " with version number: " + oldPolicy.getVersion());
215 removed.setPolicyName(oldPolicy.getId());
216 removed.setVersionNo(oldPolicy.getVersion());
217 removeFile(oldPolicy);
220 private void sendUpdate(PDPPolicy newPolicy, Map<String, PolicyDef> policyContainer) {
221 updated = new Updated();
222 // Want to know what is new ?
223 LOGGER.info("The new Policy is: " + newPolicy.getId());
224 LOGGER.info("The version no. is: " + newPolicy.getVersion());
225 updated.setPolicyName(newPolicy.getId());
226 updated.setVersionNo(newPolicy.getVersion());
227 updated.setUpdateType(UpdateType.NEW);
228 // If the policy is of Config type then retrieve its matches.
229 if (newPolicy.getName().contains(".Config_")) {
230 // Take a Configuration copy to PDP webapps.
231 final String urlStart = "attributeId=URLID,expression";
232 final String urlEnd = "}}},{";
233 String policy = policyContainer.get(newPolicy.getId()).toString();
234 if (policy.contains(urlStart)) {
235 String urlFinePartOne = policy.substring(policy.indexOf(urlStart) + urlStart.length());
236 String urlFinePart = urlFinePartOne.substring(0, urlFinePartOne.indexOf(urlEnd));
237 String urlString = urlFinePart.substring(urlFinePart.indexOf("value=$URL") + 6);
238 callPap(urlString, "Config");
240 Iterator<AnyOf> anyOfs = policyContainer.get(newPolicy.getId()).getTarget().getAnyOfs();
241 while (anyOfs.hasNext()) {
242 AnyOf anyOf = anyOfs.next();
243 Iterator<AllOf> allOfs = anyOf.getAllOfs();
244 while (allOfs.hasNext()) {
245 AllOf allOf = allOfs.next();
246 Iterator<Match> matches = allOf.getMatches();
247 HashMap<String, String> matchValues = new HashMap<>();
248 while (matches.hasNext()) {
249 Match match = matches.next();
250 LOGGER.info("Attribute Value is: " + match.getAttributeValue().getValue().toString());
251 String[] result = match.getAttributeRetrievalBase().toString().split("attributeId=");
252 result[1] = result[1].replaceAll("}", "");
253 if (!result[1].equals("urn:oasis:names:tc:xacml:1.0:subject:subject-id")) {
254 LOGGER.info("Attribute id is: " + result[1]);
256 matchValues.put(result[1], match.getAttributeValue().getValue().toString());
258 "Match is : " + result[1] + " , " + match.getAttributeValue().getValue().toString());
260 updated.setMatches(matchValues);
263 } else if (newPolicy.getName().contains(".Action_")) {
264 // Take Configuration copy to PDP Webapps.
265 // Action policies have .json as extension.
266 String urlString = "$URL/Action/" + newPolicy.getId().substring(0, newPolicy.getId().lastIndexOf('.'))
268 callPap(urlString, "Action");
272 // Adding this for Recording the changes to serve Polling requests..
273 private static String record(Notification notification) {
274 // Initialization with updates.
275 if (record.getRemovedPolicies() == null || record.getLoadedPolicies() == null) {
276 record.setRemovedPolicies(notification.getRemovedPolicies());
277 record.setLoadedPolicies(notification.getLoadedPolicies());
279 // Check if there is anything new and update the record..
280 if (record.getLoadedPolicies() != null || record.getRemovedPolicies() != null) {
281 HashSet<Removed> removedPolicies = (HashSet<Removed>) record.getRemovedPolicies();
282 HashSet<Updated> updatedPolicies = (HashSet<Updated>) record.getLoadedPolicies();
284 // Checking with New updated policies.
285 if (notification.getLoadedPolicies() != null && !notification.getLoadedPolicies().isEmpty()) {
286 for (Updated newUpdatedPolicy : notification.getLoadedPolicies()) {
287 // If it was removed earlier then we need to remove from our record
288 Iterator<Removed> oldRemovedPolicy = removedPolicies.iterator();
289 while (oldRemovedPolicy.hasNext()) {
290 Removed policy = oldRemovedPolicy.next();
291 if (newUpdatedPolicy.getPolicyName().equals(policy.getPolicyName())) {
292 if (newUpdatedPolicy.getVersionNo().equals(policy.getVersionNo())) {
293 oldRemovedPolicy.remove();
297 // If it was previously updated need to Overwrite it to the record.
298 Iterator<Updated> oldUpdatedPolicy = updatedPolicies.iterator();
299 while (oldUpdatedPolicy.hasNext()) {
300 Updated policy = oldUpdatedPolicy.next();
301 if (newUpdatedPolicy.getPolicyName().equals(policy.getPolicyName())) {
302 if (newUpdatedPolicy.getVersionNo().equals(policy.getVersionNo())) {
303 oldUpdatedPolicy.remove();
307 updatedPolicies.add(newUpdatedPolicy);
310 // Checking with New Removed policies.
311 if (notification.getRemovedPolicies() != null && !notification.getRemovedPolicies().isEmpty()) {
312 for (Removed newRemovedPolicy : notification.getRemovedPolicies()) {
313 // If it was previously removed Overwrite it to the record.
314 Iterator<Removed> oldRemovedPolicy = removedPolicies.iterator();
315 while (oldRemovedPolicy.hasNext()) {
316 Removed policy = oldRemovedPolicy.next();
317 if (newRemovedPolicy.getPolicyName().equals(policy.getPolicyName())) {
318 if (newRemovedPolicy.getVersionNo().equals(policy.getVersionNo())) {
319 oldRemovedPolicy.remove();
323 // If it was added earlier then we need to remove from our record.
324 Iterator<Updated> oldUpdatedPolicy = updatedPolicies.iterator();
325 while (oldUpdatedPolicy.hasNext()) {
326 Updated policy = oldUpdatedPolicy.next();
327 if (newRemovedPolicy.getPolicyName().equals(policy.getPolicyName())) {
328 if (newRemovedPolicy.getVersionNo().equals(policy.getVersionNo())) {
329 oldUpdatedPolicy.remove();
333 removedPolicies.add(newRemovedPolicy);
336 record.setRemovedPolicies(removedPolicies);
337 record.setLoadedPolicies(updatedPolicies);
340 // Send the Result to the caller.
341 ObjectWriter om = new ObjectMapper().writer();
344 json = om.writeValueAsString(record);
345 } catch (JsonProcessingException e) {
346 LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e.getMessage() + e);
352 private static Notification setUpdateTypes(boolean updated, boolean removed, Notification notification) {
353 if (notification != null) {
354 if (updated && removed) {
355 notification.setNotificationType(NotificationType.BOTH);
356 if (notification.getLoadedPolicies() != null) {
357 HashSet<Updated> updatedPolicies = new HashSet<>();
358 for (Updated oldUpdatedPolicy : notification.getLoadedPolicies()) {
359 Updated updatePolicy = oldUpdatedPolicy;
360 if (notification.getRemovedPolicies() != null) {
361 for (RemovedPolicy removedPolicy : notification.getRemovedPolicies()) {
362 String regex = ".(\\d)*.xml";
363 if (removedPolicy.getPolicyName().replaceAll(regex, "")
364 .equals(oldUpdatedPolicy.getPolicyName().replaceAll(regex, ""))) {
365 updatePolicy.setUpdateType(UpdateType.UPDATE);
370 updatedPolicies.add(updatePolicy);
372 notification.setLoadedPolicies(updatedPolicies);
374 } else if (updated) {
375 notification.setNotificationType(NotificationType.UPDATE);
376 } else if (removed) {
377 notification.setNotificationType(NotificationType.REMOVE);
383 private void removeFile(PDPPolicy oldPolicy) {
385 Path removedPolicyFile = Paths.get(XACMLProperties.getProperty(XacmlRestProperties.PROP_PDP_CONFIG)
386 + File.separator + oldPolicy.getId());
387 Files.deleteIfExists(removedPolicyFile);
388 boolean delete = false;
390 if (oldPolicy.getName().contains(".Config_")) {
393 XACMLProperties.getProperty(XacmlRestProperties.PROP_PDP_WEBAPPS) + File.separator + "Config");
394 } else if (oldPolicy.getName().contains(".Action_")) {
397 XACMLProperties.getProperty(XacmlRestProperties.PROP_PDP_WEBAPPS) + File.separator + "Action");
400 FileFilter fileFilter = new WildcardFileFilter(
401 oldPolicy.getId().substring(0, oldPolicy.getId().lastIndexOf('.')) + ".*");
402 File[] configFile = dir.listFiles(fileFilter);
403 if (configFile.length == 1) {
404 Files.deleteIfExists(configFile[0].toPath());
407 } catch (Exception e) {
408 LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Couldn't remove the policy/config file "
409 + oldPolicy.getName() + e);
413 private void callPap(String urlString, String type) {
414 Path configLocation = Paths
415 .get(XACMLProperties.getProperty(XacmlRestProperties.PROP_PDP_WEBAPPS) + File.separator + type);
416 if (Files.notExists(configLocation)) {
418 Files.createDirectories(configLocation);
419 } catch (IOException e) {
420 LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Failed to create config directory: "
421 + configLocation.toAbsolutePath().toString(), e);
424 PapUrlResolver papUrls = PapUrlResolver.getInstance();
425 while (papUrls.hasMoreUrls()) {
426 String papPath = papUrls.getUrl();
427 papPath = papPath.substring(0, papPath.lastIndexOf("/pap"));
428 String papAddress = urlString.replace("$URL", papPath);
429 String fileName = papAddress.substring(papAddress.lastIndexOf('/') + 1);
430 String fileLocation = configLocation.toString() + File.separator + fileName;
432 URL papURL = new URL(papAddress);
433 LOGGER.info("Calling " + papAddress + " for Configuration Copy.");
434 URLConnection urlConnection = papURL.openConnection();
435 File file = new File(fileLocation);
436 try (InputStream is = urlConnection.getInputStream(); OutputStream os = new FileOutputStream(file)) {
437 IOUtils.copy(is, os);
440 } catch (Exception e) {
441 LOGGER.error(e + e.getMessage());