eb0ecf118bfc7206de27f94bab28e503bc5600ce
[aaf/authz.git] / cadi / client / src / main / java / org / onap / aaf / cadi / locator / PropertyLocator.java
1 /**
2  * ============LICENSE_START====================================================
3  * org.onap.aaf
4  * ===========================================================================
5  * Copyright (c) 2018 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
22 package org.onap.aaf.cadi.locator;
23
24 import java.io.IOException;
25 import java.net.InetAddress;
26 import java.net.InetSocketAddress;
27 import java.net.Socket;
28 import java.net.URI;
29 import java.net.URISyntaxException;
30 import java.net.UnknownHostException;
31 import java.security.SecureRandom;
32 import java.util.ArrayList;
33 import java.util.List;
34 import java.util.Timer;
35 import java.util.TimerTask;
36
37 import org.onap.aaf.cadi.Locator;
38 import org.onap.aaf.cadi.LocatorException;
39 import org.onap.aaf.misc.env.util.Split;
40
41 public class PropertyLocator implements Locator<URI> {
42     private final URI [] orig;
43     private PLItem[] current;
44     private int end;
45     private final SecureRandom random;
46     private URI[] resolved;
47     private long lastRefreshed;
48     private long minRefresh;
49     private long backgroundRefresh;
50
51     public PropertyLocator(String locList) throws LocatorException {
52         this(locList,10000L, 1000*60*20L); // defaults, do not refresh more than once in 10 seconds, Refresh Locator every 20 mins.
53     }
54     /**
55      * comma delimited root url list
56      * 
57      * @param locList
58      * @throws LocatorException
59      */
60     public PropertyLocator(String locList, long minRefreshMillis, long backgroundRefreshMillis) throws LocatorException {
61         minRefresh = minRefreshMillis;
62         backgroundRefresh = backgroundRefreshMillis;
63         lastRefreshed=0L;
64         if (locList==null) {
65             throw new LocatorException("No Location List given for PropertyLocator");
66         }
67         String[] locarray = Split.split(',',locList);
68         List<URI> uriList = new ArrayList<>();
69         
70         random = new SecureRandom();
71         
72         for (int i=0;i<locarray.length;++i) {
73             try {
74                 int range = locarray[i].indexOf(":[");
75                 if (range<0) {
76                     uriList.add(new URI(locarray[i]));
77                 } else {
78                     String mach_colon = locarray[i].substring(0, range+1);
79                     int dash = locarray[i].indexOf('-',range+2);
80                     int brac = locarray[i].indexOf(']',dash+1);
81                     int slash = locarray[i].indexOf('/',brac);
82                     int start = Integer.parseInt(locarray[i].substring(range+2, dash));
83                     int end = Integer.parseInt(locarray[i].substring(dash+1, brac));
84                     for (int port=start;port<=end;++port) {
85                         uriList.add(new URI(mach_colon+port + (slash>=0?locarray[i].substring(slash):"")));
86                     }
87                 }
88             } catch (NumberFormatException nf) {
89                 throw new LocatorException("Invalid URI format: " + locarray[i]);
90             } catch (URISyntaxException e) {
91                 throw new LocatorException(e);
92             }
93         }
94         orig = new URI[uriList.size()];
95         uriList.toArray(orig);
96
97         refresh();
98         new Timer("PropertyLocator Refresh Timer",true).scheduleAtFixedRate(new TimerTask() {
99             @Override
100             public void run() {
101                 refresh();
102             }
103         }, backgroundRefresh,backgroundRefresh);
104     }
105
106     @Override
107     public URI get(Item item) throws LocatorException {
108         synchronized(orig) {
109             if (item==null) {
110                 return null;
111             } else {
112                 return resolved[((PLItem)item).idx];
113             }
114         }
115     }
116
117     @Override
118     public Item first() throws LocatorException {
119         return end>0?current[0]:null;
120     }
121
122     @Override
123     public boolean hasItems() {
124         return end>0;
125     }
126
127     @Override
128     public Item next(Item item) throws LocatorException {
129         if (item==null) {
130             return null;
131         } else {
132             int spot;
133             if ((spot=(((PLItem)item).order+1))>=end)return null;
134             return current[spot];
135         }
136     }
137
138     @Override
139     public synchronized void invalidate(Item item) throws LocatorException {
140         if (--end<0) {
141             refresh();
142             return;
143         }
144         if (item==null) {
145             return;
146         }
147         PLItem pli = (PLItem)item;
148         int i,order;
149         for (i=0;i<end;++i) {
150             if (pli==current[i])break;
151         }
152         order = current[i].order;
153         for (;i<end;++i) {
154             current[i]=current[i+1];
155             current[i].order=order++;
156         }
157         current[end]=pli;
158     }
159
160     @Override
161     public Item best() throws LocatorException {
162         if (current.length==0) {
163             refresh();
164         }
165         switch(current.length) {
166             case 0:
167                 return null;
168             case 1:
169                 return current[0];
170             default:
171                 int rand = random.nextInt(); // sonar driven syntax
172                 return current[Math.abs(rand)%current.length];
173         }
174     }
175
176     @Override
177     public synchronized boolean refresh() {
178         if (System.currentTimeMillis()>lastRefreshed) {
179             // Build up list
180             List<URI> resolve = new ArrayList<>();
181             String realname;
182             for (int i = 0; i < orig.length ; ++i) {
183                 try {
184                     InetAddress ia[] = InetAddress.getAllByName(orig[i].getHost());
185
186                     URI o,n;
187                     for (int j=0;j<ia.length;++j) {
188                         o = orig[i];
189                         Socket socket = createSocket();
190                         try {
191                             realname=ia[j].getHostAddress().equals(ia[j].getHostName())?ia[j].getCanonicalHostName():ia[j].getHostName();
192                             int port = o.getPort();
193                             if (port<0) { // default
194                                 port = "https".equalsIgnoreCase(o.getScheme())?443:80;
195                             }
196                             socket.connect(new InetSocketAddress(realname,port),3000);
197                             try {
198                                 if (socket.isConnected()) {
199                                     n = new URI(
200                                             o.getScheme(),
201                                             o.getUserInfo(),
202                                             realname,
203                                             o.getPort(),
204                                             o.getPath(),
205                                             o.getQuery(),
206                                             o.getFragment()
207                                             );
208                                     resolve.add(n);
209                                 }
210                             } finally {
211                                 socket.close();
212                             }
213                         } catch (IOException e) {
214                         } finally {
215                             if (!socket.isClosed()) {
216                                 try {
217                                     socket.close();
218                                 } catch (IOException e) {
219                                     // nothing to do.
220                                 }
221                             }
222                         }
223                     }
224                 } catch (UnknownHostException | URISyntaxException e) {
225                     // Note: Orig Name already known as valid, based on constructor
226                 }
227             }
228             end=resolve.size();
229             PLItem[] newCurrent;
230             if (current==null || current.length!=end) {
231                 newCurrent = new PLItem[end];
232             } else {
233                 newCurrent = current;
234             }
235     
236             for (int i=0; i< end; ++i) {
237                 if (newCurrent[i]==null){
238                     newCurrent[i]=new PLItem(i);
239                 } else {
240                     newCurrent[i].idx=newCurrent[i].order=i;
241                 }
242             }
243             synchronized(orig) {
244                 resolved = new URI[end];
245                 resolve.toArray(resolved);
246                 current = newCurrent;
247             }
248             lastRefreshed = System.currentTimeMillis()+minRefresh;
249             return !resolve.isEmpty();
250         } else {
251             return false;
252         }
253     }
254
255     protected Socket createSocket() {
256         return new Socket();
257     }
258     
259     private class PLItem implements Item {
260         public int idx,order;
261         
262         public PLItem(int i) {
263             idx = order =i;
264         }
265         
266         public String toString() {
267             return "Item: " + idx + " order: " + order;
268         }
269     }
270
271     public String toString() {
272         StringBuilder sb = new StringBuilder();
273         boolean first = true;
274         for (URI uri : orig) {
275             boolean isResolved=false;
276             if (uri!=null) {
277                 if (first) {
278                     first = false;
279                 } else {
280                     sb.append(", ");
281                 }
282                 sb.append(uri.toString());
283                 sb.append(" [");
284                 for (URI u2 : resolved) {
285                     if (uri.equals(u2)) {
286                         isResolved = true;
287                         break;
288                     }
289                 }
290                 sb.append(isResolved?"X]\n":" ]");
291             }
292         }
293         return sb.toString();
294     }
295     
296     public void destroy() {
297     }
298 }