Fixed the Policy API issues and Bugfixes
[policy/engine.git] / ECOMP-PDP-REST / src / main / java / org / openecomp / policy / pdp / rest / PapUrlResolver.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;
22
23 import java.net.URI;
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.Properties;
30
31 import org.openecomp.policy.common.logging.flexlogger.FlexLogger;
32 import org.openecomp.policy.common.logging.flexlogger.Logger;
33 import org.openecomp.policy.rest.XACMLRestProperties;
34
35 import com.att.research.xacml.util.XACMLProperties;
36
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;
41         
42         //thread locks
43         public static final Object propertyLock = new Object();
44         
45         //keeping this here for backward compatibility
46         public static String extractIdFromUrl(String url){
47                 return extractQuery(url);
48         }
49         public static String extractQuery(String url){
50                 try{
51                         return URI.create(url).getQuery();
52                 } catch(Exception e){
53                         LOGGER.error("Exception occured while extracting query. So, empty string is returned"+e);
54                         return "";
55                 }
56         }
57         public static String modifyUrl(String idUrl, String serverUrl){
58                 URI one = URI.create(idUrl);
59                 String host = one.getPath()+one.getQuery();
60                 URI two = URI.create(serverUrl);
61                 two.resolve(host);
62                 return two.toString();
63         }
64
65         //get an instance of a new PapUrlResolver, using XACMLProperties to get the url lists
66         public static PapUrlResolver getInstance(){
67                 return new PapUrlResolver(null,null,null,true);
68         }
69         
70         //get an instance of a new PapUrlResolver, using the provides strings for the url lists
71         public static PapUrlResolver getInstance(String urlList, String failedList, String succeededList){
72                 return new PapUrlResolver(urlList, failedList, succeededList,false);
73         }
74
75         //keeps track of our current location in the list of urls, allows for iterating
76         private int pointer;
77         
78         //should the XACML property lists be updated after anything changes or should we wait for the update
79         //method to be called.
80         private boolean autoUpdateProperties;
81         
82         //this list keeps the sorted, priority of PAP URLs
83         private PapUrlNode[] sortedUrlNodes;
84         //this list keeps the original list of nodes so that they can be entered into the property list correctly
85         private PapUrlNode[] originalUrlNodes;
86         
87         //private constructor to make an instance of a PapUrlResolver, called by static method getInstance.
88         //If the list property strings are not defined, we get the values from XACMLProperties.
89         //The instance acts as an iterator, with hasNext and next methods, but does not implement Iterable,
90         //because it is used for a difference purpose.
91         private PapUrlResolver(String urlList, String failedList, String succeededList, boolean autoUpdateProperties){  
92                 this.autoUpdateProperties = autoUpdateProperties;
93                 String papUrlLists = urlList;
94                 String papUrlFailedList = failedList;
95                 String papUrlSuccessList = succeededList;
96                 if(papUrlLists == null){
97                         papUrlLists = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_URLS);
98                         if(papUrlLists == null){
99                                 papUrlLists = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_URL);
100                         }
101                         papUrlFailedList = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS);
102                         papUrlSuccessList = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS);
103                 }
104                 
105                 String[] urls = papUrlLists.split(",");
106                 if(urls.length == 0){           
107                         //log error
108                 }
109                 String[] failed = emptyOrSplit(papUrlFailedList,urls.length);
110                 String[] succeeded = emptyOrSplit(papUrlSuccessList,urls.length);
111                 
112                 sortedUrlNodes = new PapUrlNode[urls.length];
113                 for(int i=0;i<urls.length;i++){
114                 
115                         String userId = null;
116                         String pass = null;
117                         userId = XACMLProperties.getProperty(urls[i]+"."+XACMLRestProperties.PROP_PAP_USERID);                                  
118                         pass = XACMLProperties.getProperty(urls[i]+"."+XACMLRestProperties.PROP_PAP_PASS);
119                         if(userId == null || pass == null){
120                                 userId = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_USERID);
121                                 pass = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_PASS);
122                         }
123                         if(userId == null || pass == null){
124                                 userId = "";
125                                 pass = "";
126                         }
127                         PapUrlNode newNode = new PapUrlNode(urls[i],userId,pass);
128                         newNode.setFailedTime(failed[i]);
129                         newNode.setSucceededTime(succeeded[i]);
130                         if(sortedUrlNodes[i] == null){
131                                 sortedUrlNodes[i] = newNode;
132                         }
133                 }
134                 originalUrlNodes = sortedUrlNodes.clone();
135                 sort(sortedUrlNodes);
136                 pointer = 0;
137         }
138         
139         
140         //either split a list by commas, or fill an array to the expected length, if the property list is not long enough
141         private String[] emptyOrSplit(String list,int expectedLength){
142                 String[] ret;
143                 if(list == null){
144                         ret = new String[expectedLength];
145                         for(int i=0;i<expectedLength;i++){
146                                 ret[i] = "-1";
147                         }
148                 } else {
149                         ret = list.split(",");
150                         if(ret.length != expectedLength){
151                                 ret = emptyOrSplit(null,expectedLength);
152                         }
153                 }
154                 return ret;
155         }
156         
157         private void sort(PapUrlNode[] array){
158                 
159                 //O(n^2) double-loop most likely the best in this case, since number of records will be VERY small
160                 for(int i=0;i<array.length;i++){
161                         for(int j=i;j<array.length;j++){
162                                 if(array[j].compareTo(array[i])<0){
163                                         PapUrlNode temp = array[i];
164                                         array[i] = array[j];
165                                         array[j] = temp;
166                                 }
167                         }
168                 }
169         }
170         
171         //returns whether this PapUrlResolver object has more PAP urls that can be tried
172         public boolean hasMoreUrls(){
173                 return pointer < sortedUrlNodes.length;
174         }
175         
176         //sets the current PAP url as being failed
177         //this will set the failed time to now and remove any succeeded time
178         public void failed(){
179                 LOGGER.error("PAP Server FAILED: "+sortedUrlNodes[pointer].getUrl());
180
181                 sortedUrlNodes[pointer].setFailedTime(new Date());
182                 sortedUrlNodes[pointer].setSucceededTime(null);
183                 propertiesUpdated();
184         }
185         
186         //sets the current PAP url as being working
187         //this will set the succeeded time to now and remove any failed time
188         //Also, this will cause hasMoreUrls to return false, since a working one has been found
189         
190         public void succeeded(){
191                 registered();
192                 pointer = sortedUrlNodes.length;
193         }
194         public void registered(){
195                 sortedUrlNodes[pointer].setFailedTime(null);
196                 sortedUrlNodes[pointer].setSucceededTime(new Date());
197                 LOGGER.info("PAP server SUCCEEDED "+sortedUrlNodes[pointer].getUrl());
198                 propertiesUpdated();
199         }
200         
201         //returns a properties object with the properties that pertain to PAP urls
202         public Properties getProperties(){
203                 String failedPropertyString = "";
204                 String succeededPropertyString = "";
205                 String urlPropertyString = "";
206                 for(int i=0;i<originalUrlNodes.length;i++){
207                         failedPropertyString = failedPropertyString.concat(",").concat(originalUrlNodes[i].getFailedTime());
208                         succeededPropertyString = succeededPropertyString.concat(",").concat(originalUrlNodes[i].getSucceededTime());
209                         urlPropertyString = urlPropertyString.concat(",").concat(originalUrlNodes[i].getUrl());
210                 }
211                 Properties prop = new Properties();
212                 failedPropertyString = failedPropertyString.substring(1);
213                 succeededPropertyString = succeededPropertyString.substring(1);
214                 urlPropertyString = urlPropertyString.substring(1);
215                 prop.setProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS,failedPropertyString);
216                 prop.setProperty(XACMLRestProperties.PROP_PAP_URLS,urlPropertyString);
217                 prop.setProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS,succeededPropertyString);
218                 return prop;
219         }
220         
221         //saves the updates urls to the correct properties
222         private void propertiesUpdated(){
223                 if(!autoUpdateProperties){
224                         return;
225                 }
226                 Properties prop = getProperties();
227
228                 LOGGER.debug("Failed PAP Url List: "+prop.getProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS));
229                 LOGGER.debug("Succeeded PAP Url List: "+prop.getProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS));
230                 XACMLProperties.setProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS,prop.getProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS));
231                 XACMLProperties.setProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS,prop.getProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS));
232         }
233         
234         //iterates to the next available PAP url, according to the priority order
235         public void getNext(){
236                 pointer++;
237         }
238         
239         //returns the url of the current PAP server that we are iterating over
240         //will append the provided policy id to the url
241         public String getUrl(String query){
242                 if(sortedUrlNodes[pointer]== null){
243                         throw new NoSuchElementException();
244                 } else {
245                         return sortedUrlNodes[pointer].getUrl().concat("?").concat(query);
246                 }
247         }
248         
249         //returns the url of the current PAP server that we are iterating over
250         //Just returns the url, with no id appended to it
251         public String getUrl(){
252                 if(sortedUrlNodes[pointer]== null){
253                         throw new NoSuchElementException();
254                 } else {        
255                         
256                         return sortedUrlNodes[pointer].getUrl();
257                 }
258         }
259         public String getUserId(){
260                 if(sortedUrlNodes[pointer]== null){
261                         throw new NoSuchElementException();
262                 } else {        
263                         
264                         return sortedUrlNodes[pointer].getUserId();
265                 }
266         }
267         public String getPass(){
268                 if(sortedUrlNodes[pointer]== null){
269                         throw new NoSuchElementException();
270                 } else {        
271                         
272                         return sortedUrlNodes[pointer].getPass();
273                 }
274         }
275
276         
277         //This is the class to hold the details of a single PAP URL
278         //including: the url itself, the last time it failed, and the last time it succeeded
279         //It also includes the custom comparer which can compare based on failed and succeeded times, and takes into account
280         //the timeout on failures.
281         private class PapUrlNode implements Comparable<PapUrlNode> {
282                 private String papUrl;
283                 private Date failedTime;
284                 private Date succeededTime;
285                 private String userId;
286                 private String pass;
287                 
288                 public PapUrlNode(String url,String userId,String pass){
289                         this.papUrl = url;
290                         failedTime = null;
291                         this.succeededTime = null;
292                         this.userId = userId;
293                         this.pass = pass;
294                         
295                 }
296                 public String getUserId(){
297                         return this.userId;
298                 }
299                 public String getPass(){
300                         return this.pass;
301                 }
302                 
303                 public void setFailedTime(Object time){
304                         Date failedTimeAsDate = setHandler(time);
305                         if(failedTimeAsDate == null){
306                                 this.failedTime = null;
307                         } else {
308                                 long timeDifference = new Date().getTime() - failedTimeAsDate.getTime();
309                                 if(timeDifference < FAIL_TIMEOUT){
310                                         this.failedTime = failedTimeAsDate;
311                                 } else {
312                                         this.failedTime = null;
313                                 }
314                         }
315                 }
316                 
317                 //set the time that this url succeeded at
318                 public void setSucceededTime(Object time){
319                         this.succeededTime = setHandler(time);
320                 }
321                 
322                 //parses string into a date or a null date, if the url never failed/succeeded (since -1 will be in the property)
323                 private Date setHandler(Object time){
324                         if(time instanceof String){
325                                 if("-1".equals((String)time)){
326                                         return null;
327                                 }
328                                 try {
329                                         DateFormat df = new SimpleDateFormat();
330                                         return df.parse((String)time);
331                                 } catch (ParseException e) {                                    
332                                         return null;
333                                 }
334                         }
335                         if(time instanceof Date){
336                                 return (Date)time;
337                         }
338                         return null;
339                 }
340                 
341                 
342                 public String getFailedTime(){
343                         return formatTime(this.failedTime);
344                 }
345                 
346                 public String getSucceededTime(){
347                         return formatTime(this.succeededTime);
348                 }
349                 
350                 //formats a Date into a string or a -1 if there is not date (-1 is used in properties for no date)
351                 private String formatTime(Date d){
352                         if(d == null){
353                                 return "-1";
354                         }
355                         DateFormat df = new SimpleDateFormat();
356                         return df.format(d);
357                 }
358                 
359                 public String getUrl(){
360                         return papUrl;
361                 }
362                 
363                 @Override
364                 public int compareTo(PapUrlNode other){
365                         if(this.failedTime == null && other.failedTime != null){
366                                 return -1;
367                         }
368                         if(this.failedTime != null && other.failedTime == null){
369                                 return 1;
370                         }
371                         if(this.failedTime != null){
372                                 return this.failedTime.compareTo(other.failedTime);
373                         }
374                         return 0;
375                 }
376         }
377 }