Initial OpenECOMP policy/engine commit
[policy/engine.git] / ECOMP-PDP-REST / src / main / java / org / openecomp / policy / pdp / rest / PapUrlResolver.java
diff --git a/ECOMP-PDP-REST/src/main/java/org/openecomp/policy/pdp/rest/PapUrlResolver.java b/ECOMP-PDP-REST/src/main/java/org/openecomp/policy/pdp/rest/PapUrlResolver.java
new file mode 100644 (file)
index 0000000..d9a3688
--- /dev/null
@@ -0,0 +1,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;
+               }
+       }
+}