aboutsummaryrefslogtreecommitdiffstats
path: root/ECOMP-PDP-REST/src/main/java/org/openecomp/policy/pdp/rest/PapUrlResolver.java
blob: d9a3688b4113e5f35b1d30869e0c130f335a6062 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
/*-
 * ============LICENSE_START=======================================================
 * ECOMP-PDP-REST
 * ================================================================================
 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
 * ================================================================================
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ============LICENSE_END=========================================================
 */

package org.openecomp.policy.pdp.rest;

import java.net.URI;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.NoSuchElementException;
import java.util.Properties;

import org.openecomp.policy.rest.XACMLRestProperties;

import com.att.research.xacml.util.XACMLProperties;

import org.openecomp.policy.common.logging.flexlogger.*;

public class PapUrlResolver {
	private static final Logger logger = FlexLogger.getLogger(PapUrlResolver.class);
	//how long to keep a pap failed before making it un-failed, in milli-seconds
	private static final long FAIL_TIMEOUT = 18000000;
	
	//thread locks
	public static Object propertyLock = new Object();
	
	public static void setPapUrls(String[] papUrls){
		
	}
	//keeping this here for backward compatibility
	public static String extractIdFromUrl(String url){
		return extractQuery(url);
	}
	public static String extractQuery(String url){
		try{
		return URI.create(url).getQuery();
		} catch(Exception e){
			return "";
		}
	}
	public static String modifyUrl(String idUrl, String serverUrl){
		URI one = URI.create(idUrl);
		String host = one.getPath()+one.getQuery();
		URI two = URI.create(serverUrl);
		two.resolve(host);
		return two.toString();
	}

	//get an instance of a new PapUrlResolver, using XACMLProperties to get the url lists
	public static PapUrlResolver getInstance(){
		return new PapUrlResolver(null,null,null,true);
	}
	
	//get an instance of a new PapUrlResolver, using the provides strings for the url lists
	public static PapUrlResolver getInstance(String urlList, String failedList, String succeededList){
		return new PapUrlResolver(urlList, failedList, succeededList,false);
	}

	//keeps track of our current location in the list of urls, allows for iterating
	private int pointer;
	
	//should the XACML property lists be updated after anything changes or should we wait for the update
	//method to be called.
	private boolean autoUpdateProperties;
	
	//this list keeps the sorted, priority of PAP URLs
	private PapUrlNode[] sortedUrlNodes;
	//this list keeps the original list of nodes so that they can be entered into the property list correctly
	private PapUrlNode[] originalUrlNodes;
	
	//private constructor to make an instance of a PapUrlResolver, called by static method getInstance.
	//If the list property strings are not defined, we get the values from XACMLProperties.
	//The instance acts as an iterator, with hasNext and next methods, but does not implement Iterable,
	//because it is used for a difference purpose.
	private PapUrlResolver(String urlList, String failedList, String succeededList, boolean autoUpdateProperties){	
		this.autoUpdateProperties = autoUpdateProperties;
		//synchronized(propertyLock){
		if(urlList == null){
			urlList = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_URLS);
			if(urlList == null){
				urlList = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_URL);
			}
			failedList = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS);
			succeededList = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS);
		}
		//}		
		String[] urls = urlList.split(",");
		if(urls.length == 0){		
			//log error
		}
		String[] failed = emptyOrSplit(failedList,urls.length);
		String[] succeeded = emptyOrSplit(succeededList,urls.length);
		
		sortedUrlNodes = new PapUrlNode[urls.length];
		for(int i=0;i<urls.length;i++){
		
			String userId = null;
			String pass = null;
			userId = XACMLProperties.getProperty(urls[i]+"."+XACMLRestProperties.PROP_PAP_USERID);					
			pass = XACMLProperties.getProperty(urls[i]+"."+XACMLRestProperties.PROP_PAP_PASS);
			if(userId == null || pass == null){
				userId = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_USERID);
				pass = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_PASS);
			}
			if(userId == null || pass == null){
				userId = "";
				pass = "";
			}
			PapUrlNode newNode = new PapUrlNode(urls[i],userId,pass);
			newNode.setFailedTime(failed[i]);
			newNode.setSucceededTime(succeeded[i]);
			if(sortedUrlNodes[i] == null){
				sortedUrlNodes[i] = newNode;
			}
			
		}
		originalUrlNodes = sortedUrlNodes.clone();
		sort(sortedUrlNodes);
		pointer = 0;
	}
	
	
	//either split a list by commas, or fill an array to the expected length, if the property list is not long enough
	private String[] emptyOrSplit(String list,int expectedLength){
		String[] ret;
		if(list == null){
			ret = new String[expectedLength];
			for(int i=0;i<expectedLength;i++){
				ret[i] = "-1";
			}
		} else {
			ret = list.split(",");
			if(ret.length != expectedLength){
				ret = emptyOrSplit(null,expectedLength);
			}
		}
		return ret;
	}
	
	private void sort(PapUrlNode[] array){
		
		//O(n^2) double-loop most likely the best in this case, since number of records will be VERY small
		for(int i=0;i<array.length;i++){
			for(int j=i;j<array.length;j++){
				if(array[j].compareTo(array[i])<0){
					PapUrlNode temp = array[i];
					array[i] = array[j];
					array[j] = temp;
				}
			}
		}
	}
	
	//returns whether this PapUrlResolver object has more PAP urls that can be tried
	public boolean hasMoreUrls(){
		return pointer < sortedUrlNodes.length;
	}
	
	//sets the current PAP url as being failed
	//this will set the failed time to now and remove any succeeded time
	public void failed(){
		logger.error("PAP Server FAILED: "+sortedUrlNodes[pointer].getUrl());

		sortedUrlNodes[pointer].setFailedTime(new Date());
		sortedUrlNodes[pointer].setSucceededTime(null);
		propertiesUpdated();
	}
	
	//sets the current PAP url as being working
	//this will set the succeeded time to now and remove any failed time
	//Also, this will cause hasMoreUrls to return false, since a working one has been found
	
	public void succeeded(){
		registered();
		pointer = sortedUrlNodes.length;
	}
	public void registered(){
		sortedUrlNodes[pointer].setFailedTime(null);
		sortedUrlNodes[pointer].setSucceededTime(new Date());
		logger.info("PAP server SUCCEEDED "+sortedUrlNodes[pointer].getUrl());
		propertiesUpdated();
	}
	
	//returns a properties object with the properties that pertain to PAP urls
	public Properties getProperties(){
		String failedPropertyString = "";
		String succeededPropertyString = "";
		String urlPropertyString = "";
		for(int i=0;i<originalUrlNodes.length;i++){
			failedPropertyString = failedPropertyString.concat(",").concat(originalUrlNodes[i].getFailedTime());
			succeededPropertyString = succeededPropertyString.concat(",").concat(originalUrlNodes[i].getSucceededTime());
			urlPropertyString = urlPropertyString.concat(",").concat(originalUrlNodes[i].getUrl());
		}
		Properties prop = new Properties();
		failedPropertyString = failedPropertyString.substring(1);
		succeededPropertyString = succeededPropertyString.substring(1);
		urlPropertyString = urlPropertyString.substring(1);
		prop.setProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS,failedPropertyString);
		prop.setProperty(XACMLRestProperties.PROP_PAP_URLS,urlPropertyString);
		prop.setProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS,succeededPropertyString);
		return prop;
	}
	
	//saves the updates urls to the correct properties
	private void propertiesUpdated(){
		if(!autoUpdateProperties){
			return;
		}
		Properties prop = getProperties();

		logger.debug("Failed PAP Url List: "+prop.getProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS));
		logger.debug("Succeeded PAP Url List: "+prop.getProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS));
		XACMLProperties.setProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS,prop.getProperty(XACMLRestProperties.PROP_PAP_FAILED_URLS));
		XACMLProperties.setProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS,prop.getProperty(XACMLRestProperties.PROP_PAP_SUCCEEDED_URLS));
	}
	
	//iterates to the next available PAP url, according to the priority order
	public void getNext(){
		pointer++;
	}
	
	//returns the url of the current PAP server that we are iterating over
	//will append the provided policy id to the url
	public String getUrl(String query){
		if(sortedUrlNodes[pointer]== null){
			throw new NoSuchElementException();
		} else {
			String finalUrl = sortedUrlNodes[pointer].getUrl().concat("?").concat(query);
			return finalUrl;
		}
	}
	
	//returns the url of the current PAP server that we are iterating over
	//Just returns the url, with no id appended to it
	public String getUrl(){
		if(sortedUrlNodes[pointer]== null){
			throw new NoSuchElementException();
		} else {	
			
			return sortedUrlNodes[pointer].getUrl();
		}
	}
	public String getUserId(){
		if(sortedUrlNodes[pointer]== null){
			throw new NoSuchElementException();
		} else {	
			
			return sortedUrlNodes[pointer].getUserId();
		}
	}
	public String getPass(){
		if(sortedUrlNodes[pointer]== null){
			throw new NoSuchElementException();
		} else {	
			
			return sortedUrlNodes[pointer].getPass();
		}
	}

	
	//This is the class to hold the details of a single PAP URL
	//including: the url itself, the last time it failed, and the last time it succeeded
	//It also includes the custom comparer which can compare based on failed and succeeded times, and takes into account
	//the timeout on failures.
	private class PapUrlNode implements Comparable<PapUrlNode> {
		private String papUrl;
		private Date failedTime;
		private Date succeededTime;
		private String userId;
		private String pass;
		
		public PapUrlNode(String url){
			this.papUrl = url;
			failedTime = null;
			this.succeededTime = null;
			this.userId = "";
			this.pass = "";
			
		}
		public PapUrlNode(String url,String userId,String pass){
			this.papUrl = url;
			failedTime = null;
			this.succeededTime = null;
			this.userId = userId;
			this.pass = pass;
			
		}
		public String getUserId(){
			return this.userId;
		}
		public String getPass(){
			return this.pass;
		}
		
		public void setFailedTime(Object time){
			Date failedTimeAsDate = setHandler(time);
			if(failedTimeAsDate == null){
				this.failedTime = null;
			} else {
				long timeDifference = new Date().getTime() - failedTimeAsDate.getTime();
				if(timeDifference < FAIL_TIMEOUT){
					this.failedTime = failedTimeAsDate;
				} else {
					this.failedTime = null;
				}
			}
		}
		
		//set the time that this url succeeded at
		public void setSucceededTime(Object time){
			this.succeededTime = setHandler(time);
		}
		
		//parses string into a date or a null date, if the url never failed/succeeded (since -1 will be in the property)
		private Date setHandler(Object time){
			if(time instanceof String){
				if(((String)time).equals("-1")){
					return null;
				}
				try {
					DateFormat df = new SimpleDateFormat();
					Date parsedTime = df.parse((String)time);
					return parsedTime;
				} catch (ParseException e) {					
					return null;
				}
			}
			if(time instanceof Date){
				return (Date)time;
			}
			return null;
		}
		
		
		public String getFailedTime(){
			return formatTime(this.failedTime);
		}
		
		public String getSucceededTime(){
			return formatTime(this.succeededTime);
		}
		
		//formats a Date into a string or a -1 if there is not date (-1 is used in properties for no date)
		private String formatTime(Date d){
			if(d == null){
				return "-1";
			}
			DateFormat df = new SimpleDateFormat();
			return df.format(d);
		}
		
		public String getUrl(){
			return papUrl;
		}

		public int compareTo(PapUrlNode other){
			if(this.failedTime == null && other.failedTime != null){
				return -1;
			}
			if(this.failedTime != null && other.failedTime == null){
				return 1;
			}
			if(this.failedTime != null){
				return this.failedTime.compareTo(other.failedTime);
			}
			return 0;
		}
	}
}