2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2019 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;
23 import com.att.research.xacml.util.XACMLProperties;
25 import java.text.DateFormat;
26 import java.text.ParseException;
27 import java.text.SimpleDateFormat;
28 import java.util.Date;
29 import java.util.NoSuchElementException;
30 import java.util.Objects;
31 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.PeCryptoUtils;
37 public class PapUrlResolver {
38 private static final Logger LOGGER = FlexLogger.getLogger(PapUrlResolver.class);
39 // how long to keep a pap failed before making it un-failed, in milli-seconds
40 private static final long FAIL_TIMEOUT = 18000000;
43 public static final Object propertyLock = new Object();
45 // keeping this here for backward compatibility
46 public static String extractIdFromUrl(String url) {
47 return extractQuery(url);
50 public static String extractQuery(String url) {
52 return URI.create(url).getQuery();
53 } catch (Exception e) {
54 LOGGER.error("Exception occured while extracting query. So, empty string is returned" + e);
59 public static String modifyUrl(String idUrl, String serverUrl) {
60 URI one = URI.create(idUrl);
61 String host = one.getPath() + one.getQuery();
62 URI two = URI.create(serverUrl);
64 return two.toString();
67 // get an instance of a new PapUrlResolver, using XACMLProperties to get the url lists
68 public static PapUrlResolver getInstance() {
69 return new PapUrlResolver(null, null, null, true);
72 // get an instance of a new PapUrlResolver, using the provides strings for the url lists
73 public static PapUrlResolver getInstance(String urlList, String failedList, String succeededList) {
74 return new PapUrlResolver(urlList, failedList, succeededList, false);
77 // keeps track of our current location in the list of urls, allows for iterating
80 // should the XACML property lists be updated after anything changes or should we wait for the update
81 // method to be called.
82 private boolean autoUpdateProperties;
84 // this list keeps the sorted, priority of PAP URLs
85 private PapUrlNode[] sortedUrlNodes;
86 // this list keeps the original list of nodes so that they can be entered into the property list correctly
87 private PapUrlNode[] originalUrlNodes;
89 // private constructor to make an instance of a PapUrlResolver, called by static method getInstance.
90 // If the list property strings are not defined, we get the values from XACMLProperties.
91 // The instance acts as an iterator, with hasNext and next methods, but does not implement Iterable,
92 // because it is used for a difference purpose.
93 private PapUrlResolver(String urlList, String failedList, String succeededList, boolean autoUpdateProperties) {
94 this.autoUpdateProperties = autoUpdateProperties;
95 String papUrlLists = urlList;
96 String papUrlFailedList = failedList;
97 String papUrlSuccessList = succeededList;
98 if (papUrlLists == null) {
99 papUrlLists = XACMLProperties.getProperty(XacmlRestProperties.PROP_PAP_URLS);
100 if (papUrlLists == null) {
101 papUrlLists = XACMLProperties.getProperty(XacmlRestProperties.PROP_PAP_URL);
103 papUrlFailedList = XACMLProperties.getProperty(XacmlRestProperties.PROP_PAP_FAILED_URLS);
104 papUrlSuccessList = XACMLProperties.getProperty(XacmlRestProperties.PROP_PAP_SUCCEEDED_URLS);
107 String[] urls = papUrlLists.split(",");
108 if (urls.length == 0) {
111 String[] failed = emptyOrSplit(papUrlFailedList, urls.length);
112 String[] succeeded = emptyOrSplit(papUrlSuccessList, urls.length);
114 sortedUrlNodes = new PapUrlNode[urls.length];
115 for (int i = 0; i < urls.length; i++) {
117 String userId = null;
119 userId = XACMLProperties.getProperty(urls[i] + "." + XacmlRestProperties.PROP_PAP_USERID);
120 pass = XACMLProperties.getProperty(urls[i] + "."
121 + PeCryptoUtils.decrypt(XACMLProperties.getProperty(XacmlRestProperties.PROP_PAP_PASS)));
122 if (userId == null || pass == null) {
123 userId = XACMLProperties.getProperty(XacmlRestProperties.PROP_PAP_USERID);
124 pass = PeCryptoUtils.decrypt(XACMLProperties.getProperty(XacmlRestProperties.PROP_PAP_PASS));
126 if (userId == null || pass == null) {
130 PapUrlNode newNode = new PapUrlNode(urls[i], userId, pass);
131 newNode.setFailedTime(failed[i]);
132 newNode.setSucceededTime(succeeded[i]);
133 if (sortedUrlNodes[i] == null) {
134 sortedUrlNodes[i] = newNode;
137 originalUrlNodes = sortedUrlNodes.clone();
138 sort(sortedUrlNodes);
142 // either split a list by commas, or fill an array to the expected length, if the property list is not long enough
143 private String[] emptyOrSplit(String list, int expectedLength) {
146 ret = new String[expectedLength];
147 for (int i = 0; i < expectedLength; i++) {
151 ret = list.split(",");
152 if (ret.length != expectedLength) {
153 ret = emptyOrSplit(null, expectedLength);
159 private void sort(PapUrlNode[] array) {
161 // O(n^2) double-loop most likely the best in this case, since number of records will be VERY small
162 for (int i = 0; i < array.length; i++) {
163 for (int j = i; j < array.length; j++) {
164 if (array[j].compareTo(array[i]) < 0) {
165 PapUrlNode temp = array[i];
173 // returns whether this PapUrlResolver object has more PAP urls that can be tried
174 public boolean hasMoreUrls() {
175 return pointer < sortedUrlNodes.length;
178 // sets the current PAP url as being failed
179 // this will set the failed time to now and remove any succeeded time
180 public void failed() {
181 LOGGER.error("PAP Server FAILED: " + sortedUrlNodes[pointer].getUrl());
183 sortedUrlNodes[pointer].setFailedTime(new Date());
184 sortedUrlNodes[pointer].setSucceededTime(null);
188 // sets the current PAP url as being working
189 // this will set the succeeded time to now and remove any failed time
190 // Also, this will cause hasMoreUrls to return false, since a working one has been found
192 public void succeeded() {
194 pointer = sortedUrlNodes.length;
197 public void registered() {
198 sortedUrlNodes[pointer].setFailedTime(null);
199 sortedUrlNodes[pointer].setSucceededTime(new Date());
200 LOGGER.info("PAP server SUCCEEDED " + sortedUrlNodes[pointer].getUrl());
204 // returns a properties object with the properties that pertain to PAP urls
205 public Properties getProperties() {
206 String failedPropertyString = "";
207 String succeededPropertyString = "";
208 String urlPropertyString = "";
209 for (int i = 0; i < originalUrlNodes.length; i++) {
210 failedPropertyString = failedPropertyString.concat(",").concat(originalUrlNodes[i].getFailedTime());
211 succeededPropertyString = succeededPropertyString.concat(",")
212 .concat(originalUrlNodes[i].getSucceededTime());
213 urlPropertyString = urlPropertyString.concat(",").concat(originalUrlNodes[i].getUrl());
215 Properties prop = new Properties();
216 failedPropertyString = failedPropertyString.substring(1);
217 succeededPropertyString = succeededPropertyString.substring(1);
218 urlPropertyString = urlPropertyString.substring(1);
219 prop.setProperty(XacmlRestProperties.PROP_PAP_FAILED_URLS, failedPropertyString);
220 prop.setProperty(XacmlRestProperties.PROP_PAP_URLS, urlPropertyString);
221 prop.setProperty(XacmlRestProperties.PROP_PAP_SUCCEEDED_URLS, succeededPropertyString);
225 // saves the updates urls to the correct properties
226 private void propertiesUpdated() {
227 if (!autoUpdateProperties) {
230 Properties prop = getProperties();
232 LOGGER.debug("Failed PAP Url List: " + prop.getProperty(XacmlRestProperties.PROP_PAP_FAILED_URLS));
233 LOGGER.debug("Succeeded PAP Url List: " + prop.getProperty(XacmlRestProperties.PROP_PAP_SUCCEEDED_URLS));
234 XACMLProperties.setProperty(XacmlRestProperties.PROP_PAP_FAILED_URLS,
235 prop.getProperty(XacmlRestProperties.PROP_PAP_FAILED_URLS));
236 XACMLProperties.setProperty(XacmlRestProperties.PROP_PAP_SUCCEEDED_URLS,
237 prop.getProperty(XacmlRestProperties.PROP_PAP_SUCCEEDED_URLS));
240 // iterates to the next available PAP url, according to the priority order
241 public void getNext() {
245 // returns the url of the current PAP server that we are iterating over
246 // will append the provided policy id to the url
247 public String getUrl(String query) {
248 if (sortedUrlNodes[pointer] == null) {
249 throw new NoSuchElementException();
251 return sortedUrlNodes[pointer].getUrl().concat("?").concat(query);
255 // returns the url of the current PAP server that we are iterating over
256 // Just returns the url, with no id appended to it
257 public String getUrl() {
258 if (sortedUrlNodes[pointer] == null) {
259 throw new NoSuchElementException();
262 return sortedUrlNodes[pointer].getUrl();
266 public String getUserId() {
267 if (sortedUrlNodes[pointer] == null) {
268 throw new NoSuchElementException();
271 return sortedUrlNodes[pointer].getUserId();
275 public String getPass() {
276 if (sortedUrlNodes[pointer] == null) {
277 throw new NoSuchElementException();
280 return sortedUrlNodes[pointer].getPass();
284 // This is the class to hold the details of a single PAP URL
285 // including: the url itself, the last time it failed, and the last time it succeeded
286 // It also includes the custom comparer which can compare based on failed and succeeded times, and takes into
288 // the timeout on failures.
289 private class PapUrlNode implements Comparable<PapUrlNode> {
290 private String papUrl;
291 private Date failedTime;
292 private Date succeededTime;
293 private String userId;
296 public PapUrlNode(String url, String userId, String pass) {
299 this.succeededTime = null;
300 this.userId = userId;
305 public String getUserId() {
309 public String getPass() {
313 public void setFailedTime(Object time) {
314 Date failedTimeAsDate = setHandler(time);
315 if (failedTimeAsDate == null) {
316 this.failedTime = null;
318 long timeDifference = new Date().getTime() - failedTimeAsDate.getTime();
319 if (timeDifference < FAIL_TIMEOUT) {
320 this.failedTime = failedTimeAsDate;
322 this.failedTime = null;
327 // set the time that this url succeeded at
328 public void setSucceededTime(Object time) {
329 this.succeededTime = setHandler(time);
332 // parses string into a date or a null date, if the url never failed/succeeded (since -1 will be in the
334 private Date setHandler(Object time) {
335 if (time instanceof String) {
336 if ("-1".equals(time)) {
340 DateFormat df = new SimpleDateFormat();
341 return df.parse((String) time);
342 } catch (ParseException e) {
346 if (time instanceof Date) {
352 public String getFailedTime() {
353 return formatTime(this.failedTime);
356 public String getSucceededTime() {
357 return formatTime(this.succeededTime);
360 // formats a Date into a string or a -1 if there is not date (-1 is used in properties for no date)
361 private String formatTime(Date d) {
365 DateFormat df = new SimpleDateFormat();
369 public String getUrl() {
374 public int compareTo(PapUrlNode other) {
375 if (this.failedTime == null && other.failedTime != null) {
378 if (this.failedTime != null && other.failedTime == null) {
381 if (this.failedTime != null) {
382 return this.failedTime.compareTo(other.failedTime);
388 public boolean equals(Object obj) {
392 if (!(obj instanceof PapUrlNode)) {
395 PapUrlNode papUrlNode = (PapUrlNode) obj;
396 return Objects.equals(papUrlNode.papUrl, papUrl) && Objects.equals(papUrlNode.failedTime, failedTime)
397 && Objects.equals(papUrlNode.succeededTime, succeededTime)
398 && Objects.equals(papUrlNode.userId, userId) && Objects.equals(papUrlNode.pass, pass);
402 public int hashCode() {
403 return Objects.hash(papUrl, failedTime, succeededTime, userId, pass);