Initial OpenECOMP policy/engine commit
[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.rest.XACMLRestProperties;
32
33 import com.att.research.xacml.util.XACMLProperties;
34
35 import org.openecomp.policy.common.logging.flexlogger.*;
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 Object propertyLock = new Object();
44         
45         public static void setPapUrls(String[] papUrls){
46                 
47         }
48         //keeping this here for backward compatibility
49         public static String extractIdFromUrl(String url){
50                 return extractQuery(url);
51         }
52         public static String extractQuery(String url){
53                 try{
54                 return URI.create(url).getQuery();
55                 } catch(Exception e){
56                         return "";
57                 }
58         }
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);
63                 two.resolve(host);
64                 return two.toString();
65         }
66
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);
70         }
71         
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);
75         }
76
77         //keeps track of our current location in the list of urls, allows for iterating
78         private int pointer;
79         
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;
83         
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;
88         
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                 //synchronized(propertyLock){
96                 if(urlList == null){
97                         urlList = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_URLS);
98                         if(urlList == null){
99                                 urlList = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_URL);
100                         }
101                         failedList = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS);
102                         succeededList = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS);
103                 }
104                 //}             
105                 String[] urls = urlList.split(",");
106                 if(urls.length == 0){           
107                         //log error
108                 }
109                 String[] failed = emptyOrSplit(failedList,urls.length);
110                 String[] succeeded = emptyOrSplit(succeededList,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                 }
135                 originalUrlNodes = sortedUrlNodes.clone();
136                 sort(sortedUrlNodes);
137                 pointer = 0;
138         }
139         
140         
141         //either split a list by commas, or fill an array to the expected length, if the property list is not long enough
142         private String[] emptyOrSplit(String list,int expectedLength){
143                 String[] ret;
144                 if(list == null){
145                         ret = new String[expectedLength];
146                         for(int i=0;i<expectedLength;i++){
147                                 ret[i] = "-1";
148                         }
149                 } else {
150                         ret = list.split(",");
151                         if(ret.length != expectedLength){
152                                 ret = emptyOrSplit(null,expectedLength);
153                         }
154                 }
155                 return ret;
156         }
157         
158         private void sort(PapUrlNode[] array){
159                 
160                 //O(n^2) double-loop most likely the best in this case, since number of records will be VERY small
161                 for(int i=0;i<array.length;i++){
162                         for(int j=i;j<array.length;j++){
163                                 if(array[j].compareTo(array[i])<0){
164                                         PapUrlNode temp = array[i];
165                                         array[i] = array[j];
166                                         array[j] = temp;
167                                 }
168                         }
169                 }
170         }
171         
172         //returns whether this PapUrlResolver object has more PAP urls that can be tried
173         public boolean hasMoreUrls(){
174                 return pointer < sortedUrlNodes.length;
175         }
176         
177         //sets the current PAP url as being failed
178         //this will set the failed time to now and remove any succeeded time
179         public void failed(){
180                 logger.error("PAP Server FAILED: "+sortedUrlNodes[pointer].getUrl());
181
182                 sortedUrlNodes[pointer].setFailedTime(new Date());
183                 sortedUrlNodes[pointer].setSucceededTime(null);
184                 propertiesUpdated();
185         }
186         
187         //sets the current PAP url as being working
188         //this will set the succeeded time to now and remove any failed time
189         //Also, this will cause hasMoreUrls to return false, since a working one has been found
190         
191         public void succeeded(){
192                 registered();
193                 pointer = sortedUrlNodes.length;
194         }
195         public void registered(){
196                 sortedUrlNodes[pointer].setFailedTime(null);
197                 sortedUrlNodes[pointer].setSucceededTime(new Date());
198                 logger.info("PAP server SUCCEEDED "+sortedUrlNodes[pointer].getUrl());
199                 propertiesUpdated();
200         }
201         
202         //returns a properties object with the properties that pertain to PAP urls
203         public Properties getProperties(){
204                 String failedPropertyString = "";
205                 String succeededPropertyString = "";
206                 String urlPropertyString = "";
207                 for(int i=0;i<originalUrlNodes.length;i++){
208                         failedPropertyString = failedPropertyString.concat(",").concat(originalUrlNodes[i].getFailedTime());
209                         succeededPropertyString = succeededPropertyString.concat(",").concat(originalUrlNodes[i].getSucceededTime());
210                         urlPropertyString = urlPropertyString.concat(",").concat(originalUrlNodes[i].getUrl());
211                 }
212                 Properties prop = new Properties();
213                 failedPropertyString = failedPropertyString.substring(1);
214                 succeededPropertyString = succeededPropertyString.substring(1);
215                 urlPropertyString = urlPropertyString.substring(1);
216                 prop.setProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS,failedPropertyString);
217                 prop.setProperty(XACMLRestProperties.PROP_PAP_URLS,urlPropertyString);
218                 prop.setProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS,succeededPropertyString);
219                 return prop;
220         }
221         
222         //saves the updates urls to the correct properties
223         private void propertiesUpdated(){
224                 if(!autoUpdateProperties){
225                         return;
226                 }
227                 Properties prop = getProperties();
228
229                 logger.debug("Failed PAP Url List: "+prop.getProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS));
230                 logger.debug("Succeeded PAP Url List: "+prop.getProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS));
231                 XACMLProperties.setProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS,prop.getProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS));
232                 XACMLProperties.setProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS,prop.getProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS));
233         }
234         
235         //iterates to the next available PAP url, according to the priority order
236         public void getNext(){
237                 pointer++;
238         }
239         
240         //returns the url of the current PAP server that we are iterating over
241         //will append the provided policy id to the url
242         public String getUrl(String query){
243                 if(sortedUrlNodes[pointer]== null){
244                         throw new NoSuchElementException();
245                 } else {
246                         String finalUrl = sortedUrlNodes[pointer].getUrl().concat("?").concat(query);
247                         return finalUrl;
248                 }
249         }
250         
251         //returns the url of the current PAP server that we are iterating over
252         //Just returns the url, with no id appended to it
253         public String getUrl(){
254                 if(sortedUrlNodes[pointer]== null){
255                         throw new NoSuchElementException();
256                 } else {        
257                         
258                         return sortedUrlNodes[pointer].getUrl();
259                 }
260         }
261         public String getUserId(){
262                 if(sortedUrlNodes[pointer]== null){
263                         throw new NoSuchElementException();
264                 } else {        
265                         
266                         return sortedUrlNodes[pointer].getUserId();
267                 }
268         }
269         public String getPass(){
270                 if(sortedUrlNodes[pointer]== null){
271                         throw new NoSuchElementException();
272                 } else {        
273                         
274                         return sortedUrlNodes[pointer].getPass();
275                 }
276         }
277
278         
279         //This is the class to hold the details of a single PAP URL
280         //including: the url itself, the last time it failed, and the last time it succeeded
281         //It also includes the custom comparer which can compare based on failed and succeeded times, and takes into account
282         //the timeout on failures.
283         private class PapUrlNode implements Comparable<PapUrlNode> {
284                 private String papUrl;
285                 private Date failedTime;
286                 private Date succeededTime;
287                 private String userId;
288                 private String pass;
289                 
290                 public PapUrlNode(String url){
291                         this.papUrl = url;
292                         failedTime = null;
293                         this.succeededTime = null;
294                         this.userId = "";
295                         this.pass = "";
296                         
297                 }
298                 public PapUrlNode(String url,String userId,String pass){
299                         this.papUrl = url;
300                         failedTime = null;
301                         this.succeededTime = null;
302                         this.userId = userId;
303                         this.pass = pass;
304                         
305                 }
306                 public String getUserId(){
307                         return this.userId;
308                 }
309                 public String getPass(){
310                         return this.pass;
311                 }
312                 
313                 public void setFailedTime(Object time){
314                         Date failedTimeAsDate = setHandler(time);
315                         if(failedTimeAsDate == null){
316                                 this.failedTime = null;
317                         } else {
318                                 long timeDifference = new Date().getTime() - failedTimeAsDate.getTime();
319                                 if(timeDifference < FAIL_TIMEOUT){
320                                         this.failedTime = failedTimeAsDate;
321                                 } else {
322                                         this.failedTime = null;
323                                 }
324                         }
325                 }
326                 
327                 //set the time that this url succeeded at
328                 public void setSucceededTime(Object time){
329                         this.succeededTime = setHandler(time);
330                 }
331                 
332                 //parses string into a date or a null date, if the url never failed/succeeded (since -1 will be in the property)
333                 private Date setHandler(Object time){
334                         if(time instanceof String){
335                                 if(((String)time).equals("-1")){
336                                         return null;
337                                 }
338                                 try {
339                                         DateFormat df = new SimpleDateFormat();
340                                         Date parsedTime = df.parse((String)time);
341                                         return parsedTime;
342                                 } catch (ParseException e) {                                    
343                                         return null;
344                                 }
345                         }
346                         if(time instanceof Date){
347                                 return (Date)time;
348                         }
349                         return null;
350                 }
351                 
352                 
353                 public String getFailedTime(){
354                         return formatTime(this.failedTime);
355                 }
356                 
357                 public String getSucceededTime(){
358                         return formatTime(this.succeededTime);
359                 }
360                 
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){
363                         if(d == null){
364                                 return "-1";
365                         }
366                         DateFormat df = new SimpleDateFormat();
367                         return df.format(d);
368                 }
369                 
370                 public String getUrl(){
371                         return papUrl;
372                 }
373
374                 public int compareTo(PapUrlNode other){
375                         if(this.failedTime == null && other.failedTime != null){
376                                 return -1;
377                         }
378                         if(this.failedTime != null && other.failedTime == null){
379                                 return 1;
380                         }
381                         if(this.failedTime != null){
382                                 return this.failedTime.compareTo(other.failedTime);
383                         }
384                         return 0;
385                 }
386         }
387 }