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