Clean up Sonar results 3
[aaf/authz.git] / cadi / aaf / src / main / java / org / onap / aaf / cadi / aaf / v2_0 / AbsAAFLocator.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.aaf.v2_0;
23
24 import java.net.URI;
25 import java.net.URISyntaxException;
26 import java.security.SecureRandom;
27 import java.util.ArrayList;
28 import java.util.Iterator;
29 import java.util.LinkedList;
30 import java.util.List;
31 import java.util.NoSuchElementException;
32
33 import org.onap.aaf.cadi.Access;
34 import org.onap.aaf.cadi.Access.Level;
35 import org.onap.aaf.cadi.Locator;
36 import org.onap.aaf.cadi.LocatorException;
37 import org.onap.aaf.cadi.config.Config;
38 import org.onap.aaf.cadi.locator.PropertyLocator;
39 import org.onap.aaf.cadi.routing.GreatCircle;
40 import org.onap.aaf.misc.env.Trans;
41 import org.onap.aaf.misc.env.util.Split;
42
43 import locate.v1_0.Endpoint;
44
45 public abstract class AbsAAFLocator<TRANS extends Trans> implements Locator<URI> {
46         protected static final SecureRandom sr = new SecureRandom();
47         private static LocatorCreator locatorCreator;
48         protected final Access access;
49
50         protected final double latitude;
51         protected final double longitude;
52         protected List<EP> epList;
53         protected final String name, version;
54         private String pathInfo = null;
55         private String query = null;
56         private String fragment = null;
57         private boolean additional = false;
58         protected String myhostname;
59         protected int myport;
60         protected final String aaf_locator_host;
61         private long earliest;
62         private final long refreshWait;
63
64
65         public AbsAAFLocator(Access access, String name, final long refreshMin) throws LocatorException {
66                 aaf_locator_host = access.getProperty(Config.AAF_LOCATE_URL, null);
67
68                 epList = new LinkedList<EP>();
69                 refreshWait = refreshMin;
70
71                 this.access = access;
72                 String lat = access.getProperty(Config.CADI_LATITUDE,null);
73                 String lng = access.getProperty(Config.CADI_LONGITUDE,null);
74                 if(lat==null || lng==null) {
75                         throw new LocatorException(Config.CADI_LATITUDE + " and " + Config.CADI_LONGITUDE + " properties are required.");
76                 } else {
77                         latitude = Double.parseDouble(lat);
78                         longitude = Double.parseDouble(lng);
79                 }
80                 if(name.startsWith("http")) { // simple URL
81                         this.name = name;
82                         this.version = Config.AAF_DEFAULT_VERSION;
83                 } else {
84                         String[] split = Split.split(':', name);
85                         
86                         switch(split.length) {
87                                 case 1:
88                                         this.name = split[0];
89                                         this.version = Config.AAF_DEFAULT_VERSION;
90                                         break;
91                                 case 0:
92                                         this.name = name;
93                                         this.version = Config.AAF_DEFAULT_VERSION;
94                                         break;
95                                 default:
96                                         this.version = split[1];
97                                         this.name = split[0];
98                                         
99                         }
100                 }
101                 
102         }
103
104         /**
105          * This is the way to setup specialized AAFLocators ahead of time.
106          * @param preload
107          */
108         public static void setCreator(LocatorCreator lc) {
109                 locatorCreator = lc; 
110         }
111         
112         public static Locator<URI> create(String key) throws LocatorException {
113                 String name = null;
114                 String version = Config.AAF_DEFAULT_VERSION;
115                 String pathInfo = null;
116                 int prev = key.indexOf("/locate");
117                 if(prev>0) {
118                         prev = key.indexOf('/',prev+6);
119                         if(prev>0) {
120                                 int next = key.indexOf('/',++prev);
121                                 if(next>0) {
122                                         name = key.substring(prev, next);
123                                         pathInfo=key.substring(next);
124                                 } else {
125                                         name = key.substring(prev);
126                                 }
127                                 String[] split = Split.split(':', name);
128                                 switch(split.length) {
129                                         case 3:
130                                         case 2:
131                                                 version = split[1];
132                                                 name = split[0];
133                                                 break;
134                                 }
135                         }
136                 }
137
138                 if(key.startsWith("http")) {
139                         if(name!=null) {
140                                 if(locatorCreator != null) {
141                                         if(name!=null) {
142                                                 AbsAAFLocator<?> aal = locatorCreator.create(name, version);
143                                                 if(pathInfo!=null) {
144                                                         aal.setPathInfo(pathInfo);
145                                                 }
146                                                 return aal;
147                                         }
148                                 }
149                         } else {
150                                 return new PropertyLocator(key);
151                         }
152                 }
153                 return null;
154         }
155         
156         public static Locator<URI> create(final String name, final String version) throws LocatorException {
157                 return locatorCreator.create(name, version);
158         }
159
160         public interface LocatorCreator {
161                 public AbsAAFLocator<?> create(String key, String version) throws LocatorException;
162                 public void setSelf(String hostname, int port);
163         }
164
165         protected static String nameFromLocatorURI(URI locatorURI) {
166                 String[] path = Split.split('/', locatorURI.getPath());
167                 if(path.length>2 && "locate".equals(path[1])) {
168                         return path[2];
169                 } else {
170                         return locatorURI.toString();
171                 }
172         }
173         
174         /**
175          * Setting "self" excludes this service from the list.  Critical for contacting peers. 
176          */
177         public void setSelf(final String hostname, final int port) {
178                 myhostname=hostname;
179                 myport=port;
180         }
181
182
183         public static void setCreatorSelf(final String hostname, final int port) {
184                 if(locatorCreator!=null) {
185                         locatorCreator.setSelf(hostname,port);
186                 }
187         }
188
189         protected final synchronized void replace(List<EP> list) {
190                 epList = list;
191         }
192         
193         /**
194          * Call _refresh as needed during calls, but actual refresh will not occur if there
195          * are existing entities or if it has been called in the last 10 (settable) seconds.  
196          * Timed Refreshes happen by Scheduled Thread
197          */
198         private final boolean _refresh() {
199                 boolean rv = false;
200                 long now=System.currentTimeMillis();
201                 if(noEntries()) {
202                         if(earliest<now) {
203                                 synchronized(epList) {
204                                         rv = refresh();
205                                         earliest = now + refreshWait; // call only up to 10 seconds.
206                                 }
207                         } else {
208                                 access.log(Level.ERROR, "Must wait at least " + refreshWait/1000 + " seconds for Locator Refresh");
209                         }
210                 }
211                 return rv;
212         }
213
214         private boolean noEntries() {
215                 return epList.size()<=0;
216         }
217
218         @Override
219         public URI get(Item item) throws LocatorException {
220                 if(item==null) {
221                         return null;
222                 } else if(item instanceof AAFLItem) {
223                         return getURI(((AAFLItem)item).uri);
224                 } else {
225                         throw new LocatorException(item.getClass().getName() + " does not belong to AAFLocator");
226                 }
227         }
228
229         @Override
230         public boolean hasItems() {
231                 boolean isEmpty = epList.isEmpty();
232                 if(!isEmpty) {
233                         for(Iterator<EP> iter = epList.iterator(); iter.hasNext(); ) {
234                                 EP ep = iter.next();
235                                 if(ep.valid) {
236                                         return true;
237                                 }
238                         }
239                         isEmpty = true;
240                 }
241                 if(_refresh()) { // is refreshed... check again
242                         isEmpty = epList.isEmpty();
243                 }
244                 return !isEmpty;
245         }
246
247         @Override
248         public void invalidate(Item item) throws LocatorException {
249                 if(item!=null) {
250                         if(item instanceof AAFLItem) {
251                                 AAFLItem ali =(AAFLItem)item; 
252                                 EP ep = ali.ep;
253                                 synchronized(epList) {
254                                         epList.remove(ep);
255                                 }
256                                 ep.invalid();
257                                 ali.iter = getIterator(); // for next guy... fresh iterator
258                         } else {
259                                 throw new LocatorException(item.getClass().getName() + " does not belong to AAFLocator");
260                         }
261                 }
262         }
263
264         @Override
265         public Item best() throws LocatorException {
266                 if(!hasItems()) {
267                         throw new LocatorException("No Entries found" + (pathInfo==null?"":(" for " + pathInfo)));
268                 }
269                 List<EP> lep = new ArrayList<EP>();
270                 EP first = null;
271                 // Note: Deque is sorted on the way by closest distance
272                 Iterator<EP> iter = getIterator();
273                 EP ep;
274                 while(iter.hasNext()) {
275                         ep = iter.next();
276                         if(ep.valid) {
277                                 if(first==null) {
278                                         first = ep;
279                                         lep.add(first);
280                                 } else {
281                                         if(Math.abs(ep.distance-first.distance)<.1) { // allow for nearby/precision issues.
282                                                 lep.add(ep);
283                                         } else {
284                                                 break;
285                                         }
286                                 }
287                         }
288                 }
289                 switch(lep.size()) {
290                         case 0:
291                                 return null;
292                         case 1:
293                                 return new AAFLItem(iter,first);
294                         default:
295                                 int rand = sr.nextInt(); // Sonar chokes without.
296                                 int i = Math.abs(rand)%lep.size();
297                                 if(i<0) {
298                                         return null;
299                                 } else {
300                                         return new AAFLItem(iter,lep.get(i));
301                                 }
302                         
303                 }
304         }
305
306         private Iterator<EP> getIterator() {
307                 Object[] epa = epList.toArray();
308                 if(epa.length==0) {
309                         _refresh();
310                         epa = epList.toArray();
311                 }
312                 return new EPIterator(epa, epList);
313         }
314
315         public class EPIterator implements Iterator<EP> {
316                 private final Object[] epa;
317                 private final List<EP> epList;
318                 private int idx;
319                 
320                 public EPIterator(Object[] epa, List<EP> epList) {
321                         this.epa = epa;
322                         this.epList = epList;
323                         idx = epa.length>0?0:-1;
324                 }
325
326                 @Override
327                 public boolean hasNext() {
328                         if(idx<0) {
329                                 return false;
330                         } else {
331                                 Object obj;
332                                 while(idx<epa.length) {
333                                         if((obj=epa[idx])==null || !((EP)obj).valid) {
334                                                 ++idx;
335                                                 continue;
336                                         }
337                                         break;
338                                 }
339                                 return idx<epa.length;
340                         }
341                 }
342
343                 @Override
344                 public EP next() {
345                         if(!hasNext() ) {
346                                 throw new NoSuchElementException();
347                         }
348                         return (EP)epa[idx++];
349                 }
350
351                 @Override
352                 public void remove() {
353                         if(idx>=0 && idx<epa.length) {
354                                 synchronized(epList) {
355                                         epList.remove(epa[idx]);
356                                 }
357                         }
358                 }
359         }
360         
361         @Override
362         public Item first()  {
363                 Iterator<EP> iter = getIterator();
364                 EP ep = AAFLItem.next(iter);
365                 if(ep==null) {
366                         return null;
367                 }
368                 return new AAFLItem(iter,ep);
369         }
370
371         @Override
372         public Item next(Item prev) throws LocatorException {
373                 if(prev==null) {
374                         StringBuilder sb = new StringBuilder("Locator Item passed in next(item) is null.");
375                         int lines = 0;
376                         for(StackTraceElement st : Thread.currentThread().getStackTrace()) {
377                                 sb.append("\n\t");
378                                 sb.append(st.toString());
379                                 if(++lines > 5) {
380                                         sb.append("\n\t...");
381                                         break;
382                                 }
383                         }
384                         access.log(Level.ERROR, sb);
385                 } else {
386                         if(prev instanceof AAFLItem) {
387                                 AAFLItem ali = (AAFLItem)prev;
388                                 EP ep = AAFLItem.next(ali.iter);
389                                 if(ep!=null) {
390                                         return new AAFLItem(ali.iter,ep);
391                                 }
392                         } else {
393                                 throw new LocatorException(prev.getClass().getName() + " does not belong to AAFLocator");
394                         }
395                 }
396                 return null;
397         }
398
399         protected static class AAFLItem implements Item {
400                         private Iterator<EP> iter;
401                         private URI uri;
402                         private EP ep;
403         
404                         public AAFLItem(Iterator<EP> iter, EP ep) {
405                                 this.iter = iter;
406                                 this.ep = ep;
407                                 uri = ep.uri;
408                         }
409                         
410                         private static EP next(Iterator<EP> iter) {
411                                 EP ep=null;
412                                 while(iter.hasNext() && (ep==null || !ep.valid)) {
413                                         ep = iter.next();
414                                 }
415                                 return ep;
416                         }
417                         
418                         public String toString() {
419                                 return ep==null?"Locator Item Invalid":ep.toString();
420                         }
421                 }
422
423         protected static class EP implements Comparable<EP> {
424                 public URI uri;
425                 public final double distance;
426                 private boolean valid;
427                 
428                 public EP(final Endpoint ep, double latitude, double longitude) throws URISyntaxException {
429                         uri = new URI(ep.getProtocol(),null,ep.getHostname(),ep.getPort(),null,null,null);
430                         distance = GreatCircle.calc(latitude, longitude, ep.getLatitude(), ep.getLongitude());
431                         valid = true;
432                 }
433
434                 public void invalid() {
435                         valid = false;
436                 }
437
438                 @Override
439                 public int compareTo(EP o) {
440                         if(distance<o.distance) {
441                                 return -1;
442                         } else if(distance>o.distance) {
443                                 return 1;
444                         } else {
445                                 return 0;
446                         }
447                 }
448                 
449                 @Override
450                 public String toString() {
451                         return distance + ": " + uri + (valid?" valid":" invalidate");
452                 }
453         }
454         
455         /* (non-Javadoc)
456          * @see org.onap.aaf.cadi.Locator#destroy()
457          */
458         @Override
459         public void destroy() {
460                 // Nothing to do
461         }
462         
463         @Override
464         public String toString() {
465                 return "AAFLocator for " + name + " on " + getURI();
466         }
467
468         public AbsAAFLocator<TRANS> setPathInfo(String pathInfo) {
469                 this.pathInfo = pathInfo;
470                 additional=true;
471                 return this;
472         }
473
474         public AbsAAFLocator<TRANS> setQuery(String query) {
475                 this.query = query;
476                 additional=true;
477                 return this;
478         }
479
480         public AbsAAFLocator<TRANS>  setFragment(String fragment) {
481                 this.fragment = fragment;
482                 additional=true;
483                 return this;
484         }
485
486         // Core URI, for reporting purposes
487         protected abstract URI getURI();
488
489         protected URI getURI(URI rv) throws LocatorException {
490                 if(additional) {
491                         try {
492                                 return new URI(rv.getScheme(),rv.getUserInfo(),rv.getHost(),rv.getPort(),pathInfo,query,fragment);
493                         } catch (URISyntaxException e) {
494                                 throw new LocatorException("Error coping URL");
495                         }
496                 }
497                 return rv;
498         }
499
500
501 }