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;
24 import java.text.DateFormat;
25 import java.text.ParseException;
26 import java.text.SimpleDateFormat;
27 import java.util.Date;
28 import java.util.NoSuchElementException;
29 import java.util.Objects;
30 import java.util.Properties;
32 import org.onap.policy.common.logging.flexlogger.FlexLogger;
33 import org.onap.policy.common.logging.flexlogger.Logger;
34 import org.onap.policy.rest.XACMLRestProperties;
35 import org.onap.policy.utils.CryptoUtils;
37 import com.att.research.xacml.util.XACMLProperties;
39 public class PapUrlResolver {
40 private static final Logger LOGGER = FlexLogger.getLogger(PapUrlResolver.class);
41 // how long to keep a pap failed before making it un-failed, in milli-seconds
42 private static final long FAIL_TIMEOUT = 18000000;
45 public static final Object propertyLock = new Object();
47 // keeping this here for backward compatibility
48 public static String extractIdFromUrl(String url) {
49 return extractQuery(url);
52 public static String extractQuery(String url) {
54 return URI.create(url).getQuery();
55 } catch (Exception e) {
56 LOGGER.error("Exception occured while extracting query. So, empty string is returned" + e);
61 public static String modifyUrl(String idUrl, String serverUrl) {
62 URI one = URI.create(idUrl);
63 String host = one.getPath() + one.getQuery();
64 URI two = URI.create(serverUrl);
66 return two.toString();
69 // get an instance of a new PapUrlResolver, using XACMLProperties to get the url lists
70 public static PapUrlResolver getInstance() {
71 return new PapUrlResolver(null, null, null, true);
74 // get an instance of a new PapUrlResolver, using the provides strings for the url lists
75 public static PapUrlResolver getInstance(String urlList, String failedList, String succeededList) {
76 return new PapUrlResolver(urlList, failedList, succeededList, false);
79 // keeps track of our current location in the list of urls, allows for iterating
82 // should the XACML property lists be updated after anything changes or should we wait for the update
83 // method to be called.
84 private boolean autoUpdateProperties;
86 // this list keeps the sorted, priority of PAP URLs
87 private PapUrlNode[] sortedUrlNodes;
88 // this list keeps the original list of nodes so that they can be entered into the property list correctly
89 private PapUrlNode[] originalUrlNodes;
91 // private constructor to make an instance of a PapUrlResolver, called by static method getInstance.
92 // If the list property strings are not defined, we get the values from XACMLProperties.
93 // The instance acts as an iterator, with hasNext and next methods, but does not implement Iterable,
94 // because it is used for a difference purpose.
95 private PapUrlResolver(String urlList, String failedList, String succeededList, boolean autoUpdateProperties) {
96 this.autoUpdateProperties = autoUpdateProperties;
97 String papUrlLists = urlList;
98 String papUrlFailedList = failedList;
99 String papUrlSuccessList = succeededList;
100 if (papUrlLists == null) {
101 papUrlLists = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_URLS);
102 if (papUrlLists == null) {
103 papUrlLists = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_URL);
105 papUrlFailedList = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS);
106 papUrlSuccessList = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS);
109 String[] urls = papUrlLists.split(",");
110 if (urls.length == 0) {
113 String[] failed = emptyOrSplit(papUrlFailedList, urls.length);
114 String[] succeeded = emptyOrSplit(papUrlSuccessList, urls.length);
116 sortedUrlNodes = new PapUrlNode[urls.length];
117 for (int i = 0; i < urls.length; i++) {
119 String userId = null;
121 userId = XACMLProperties.getProperty(urls[i] + "." + XACMLRestProperties.PROP_PAP_USERID);
122 pass = XACMLProperties.getProperty(urls[i] + "." + CryptoUtils.decryptTxtNoExStr(XACMLRestProperties.PROP_PAP_PASS));
123 if (userId == null || pass == null) {
124 userId = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_USERID);
125 pass = CryptoUtils.decryptTxtNoExStr(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_PASS));
127 if (userId == null || pass == null) {
131 PapUrlNode newNode = new PapUrlNode(urls[i], userId, pass);
132 newNode.setFailedTime(failed[i]);
133 newNode.setSucceededTime(succeeded[i]);
134 if (sortedUrlNodes[i] == null) {
135 sortedUrlNodes[i] = newNode;
138 originalUrlNodes = sortedUrlNodes.clone();
139 sort(sortedUrlNodes);
143 // either split a list by commas, or fill an array to the expected length, if the property list is not long enough
144 private String[] emptyOrSplit(String list, int expectedLength) {
147 ret = new String[expectedLength];
148 for (int i = 0; i < expectedLength; i++) {
152 ret = list.split(",");
153 if (ret.length != expectedLength) {
154 ret = emptyOrSplit(null, expectedLength);
160 private void sort(PapUrlNode[] array) {
162 // O(n^2) double-loop most likely the best in this case, since number of records will be VERY small
163 for (int i = 0; i < array.length; i++) {
164 for (int j = i; j < array.length; j++) {
165 if (array[j].compareTo(array[i]) < 0) {
166 PapUrlNode temp = array[i];
174 // returns whether this PapUrlResolver object has more PAP urls that can be tried
175 public boolean hasMoreUrls() {
176 return pointer < sortedUrlNodes.length;
179 // sets the current PAP url as being failed
180 // this will set the failed time to now and remove any succeeded time
181 public void failed() {
182 LOGGER.error("PAP Server FAILED: " + sortedUrlNodes[pointer].getUrl());
184 sortedUrlNodes[pointer].setFailedTime(new Date());
185 sortedUrlNodes[pointer].setSucceededTime(null);
189 // sets the current PAP url as being working
190 // this will set the succeeded time to now and remove any failed time
191 // Also, this will cause hasMoreUrls to return false, since a working one has been found
193 public void succeeded() {
195 pointer = sortedUrlNodes.length;
198 public void registered() {
199 sortedUrlNodes[pointer].setFailedTime(null);
200 sortedUrlNodes[pointer].setSucceededTime(new Date());
201 LOGGER.info("PAP server SUCCEEDED " + sortedUrlNodes[pointer].getUrl());
205 // returns a properties object with the properties that pertain to PAP urls
206 public Properties getProperties() {
207 String failedPropertyString = "";
208 String succeededPropertyString = "";
209 String urlPropertyString = "";
210 for (int i = 0; i < originalUrlNodes.length; i++) {
211 failedPropertyString = failedPropertyString.concat(",").concat(originalUrlNodes[i].getFailedTime());
212 succeededPropertyString = succeededPropertyString.concat(",")
213 .concat(originalUrlNodes[i].getSucceededTime());
214 urlPropertyString = urlPropertyString.concat(",").concat(originalUrlNodes[i].getUrl());
216 Properties prop = new Properties();
217 failedPropertyString = failedPropertyString.substring(1);
218 succeededPropertyString = succeededPropertyString.substring(1);
219 urlPropertyString = urlPropertyString.substring(1);
220 prop.setProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS, failedPropertyString);
221 prop.setProperty(XACMLRestProperties.PROP_PAP_URLS, urlPropertyString);
222 prop.setProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS, succeededPropertyString);
226 // saves the updates urls to the correct properties
227 private void propertiesUpdated() {
228 if (!autoUpdateProperties) {
231 Properties prop = getProperties();
233 LOGGER.debug("Failed PAP Url List: " + prop.getProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS));
234 LOGGER.debug("Succeeded PAP Url List: " + prop.getProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS));
235 XACMLProperties.setProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS,
236 prop.getProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS));
237 XACMLProperties.setProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS,
238 prop.getProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS));
241 // iterates to the next available PAP url, according to the priority order
242 public void getNext() {
246 // returns the url of the current PAP server that we are iterating over
247 // will append the provided policy id to the url
248 public String getUrl(String query) {
249 if (sortedUrlNodes[pointer] == null) {
250 throw new NoSuchElementException();
252 return sortedUrlNodes[pointer].getUrl().concat("?").concat(query);
256 // returns the url of the current PAP server that we are iterating over
257 // Just returns the url, with no id appended to it
258 public String getUrl() {
259 if (sortedUrlNodes[pointer] == null) {
260 throw new NoSuchElementException();
263 return sortedUrlNodes[pointer].getUrl();
267 public String getUserId() {
268 if (sortedUrlNodes[pointer] == null) {
269 throw new NoSuchElementException();
272 return sortedUrlNodes[pointer].getUserId();
276 public String getPass() {
277 if (sortedUrlNodes[pointer] == null) {
278 throw new NoSuchElementException();
281 return sortedUrlNodes[pointer].getPass();
285 // This is the class to hold the details of a single PAP URL
286 // including: the url itself, the last time it failed, and the last time it succeeded
287 // It also includes the custom comparer which can compare based on failed and succeeded times, and takes into
289 // the timeout on failures.
290 private class PapUrlNode implements Comparable<PapUrlNode> {
291 private String papUrl;
292 private Date failedTime;
293 private Date succeededTime;
294 private String userId;
297 public PapUrlNode(String url, String userId, String pass) {
300 this.succeededTime = null;
301 this.userId = userId;
306 public String getUserId() {
310 public String getPass() {
314 public void setFailedTime(Object time) {
315 Date failedTimeAsDate = setHandler(time);
316 if (failedTimeAsDate == null) {
317 this.failedTime = null;
319 long timeDifference = new Date().getTime() - failedTimeAsDate.getTime();
320 if (timeDifference < FAIL_TIMEOUT) {
321 this.failedTime = failedTimeAsDate;
323 this.failedTime = null;
328 // set the time that this url succeeded at
329 public void setSucceededTime(Object time) {
330 this.succeededTime = setHandler(time);
333 // parses string into a date or a null date, if the url never failed/succeeded (since -1 will be in the
335 private Date setHandler(Object time) {
336 if (time instanceof String) {
337 if ("-1".equals((String) time)) {
341 DateFormat df = new SimpleDateFormat();
342 return df.parse((String) time);
343 } catch (ParseException e) {
347 if (time instanceof Date) {
353 public String getFailedTime() {
354 return formatTime(this.failedTime);
357 public String getSucceededTime() {
358 return formatTime(this.succeededTime);
361 // formats a Date into a string or a -1 if there is not date (-1 is used in properties for no date)
362 private String formatTime(Date d) {
366 DateFormat df = new SimpleDateFormat();
370 public String getUrl() {
375 public int compareTo(PapUrlNode other) {
376 if (this.failedTime == null && other.failedTime != null) {
379 if (this.failedTime != null && other.failedTime == null) {
382 if (this.failedTime != null) {
383 return this.failedTime.compareTo(other.failedTime);
389 public boolean equals(Object obj) {
393 if (!(obj instanceof PapUrlNode)) {
396 PapUrlNode papUrlNode = (PapUrlNode) obj;
397 return Objects.equals(papUrlNode.papUrl, papUrl) && Objects.equals(papUrlNode.failedTime, failedTime)
398 && Objects.equals(papUrlNode.succeededTime, succeededTime)
399 && Objects.equals(papUrlNode.userId, userId) && Objects.equals(papUrlNode.pass, pass);
403 public int hashCode() {
404 return Objects.hash(papUrl, failedTime, succeededTime, userId, pass);