2 * ============LICENSE_START====================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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====================================================
22 package org.onap.aaf.cadi.aaf.v2_0;
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;
32 import org.onap.aaf.cadi.Access;
33 import org.onap.aaf.cadi.Access.Level;
34 import org.onap.aaf.cadi.Locator;
35 import org.onap.aaf.cadi.LocatorException;
36 import org.onap.aaf.cadi.config.Config;
37 import org.onap.aaf.cadi.locator.PropertyLocator;
38 import org.onap.aaf.cadi.routing.GreatCircle;
39 import org.onap.aaf.misc.env.Trans;
40 import org.onap.aaf.misc.env.util.Split;
42 import locate.v1_0.Endpoint;
44 public abstract class AbsAAFLocator<TRANS extends Trans> implements Locator<URI> {
45 protected static final SecureRandom sr = new SecureRandom();
46 private static LocatorCreator locatorCreator;
47 protected final Access access;
49 protected final double latitude;
50 protected final double longitude;
51 protected List<EP> epList;
52 protected final String name, version;
53 private String pathInfo = null;
54 private String query = null;
55 private String fragment = null;
56 private boolean additional = false;
57 protected String myhostname;
59 protected final String aaf_locator_host;
60 private long earliest;
61 private final long refreshWait;
64 public AbsAAFLocator(Access access, String name, final long refreshMin) throws LocatorException {
65 aaf_locator_host = access.getProperty(Config.AAF_LOCATE_URL, null);
67 epList = new LinkedList<EP>();
68 refreshWait = refreshMin;
71 String lat = access.getProperty(Config.CADI_LATITUDE,null);
72 String lng = access.getProperty(Config.CADI_LONGITUDE,null);
73 if(lat==null || lng==null) {
74 throw new LocatorException(Config.CADI_LATITUDE + " and " + Config.CADI_LONGITUDE + " properties are required.");
76 latitude = Double.parseDouble(lat);
77 longitude = Double.parseDouble(lng);
79 if(name.startsWith("http")) { // simple URL
81 this.version = Config.AAF_DEFAULT_VERSION;
83 String[] split = Split.split(':', name);
85 switch(split.length) {
88 this.version = Config.AAF_DEFAULT_VERSION;
92 this.version = Config.AAF_DEFAULT_VERSION;
95 this.version = split[1];
104 * This is the way to setup specialized AAFLocators ahead of time.
107 public static void setCreator(LocatorCreator lc) {
111 public static Locator<URI> create(String key) throws LocatorException {
113 String version = Config.AAF_DEFAULT_VERSION;
114 String pathInfo = null;
115 int prev = key.indexOf("/locate");
117 prev = key.indexOf('/',prev+6);
119 int next = key.indexOf('/',++prev);
121 name = key.substring(prev, next);
122 pathInfo=key.substring(next);
124 name = key.substring(prev);
126 String[] split = Split.split(':', name);
127 switch(split.length) {
137 if(key.startsWith("http")) {
139 if(locatorCreator != null) {
141 AbsAAFLocator<?> aal = locatorCreator.create(name, version);
143 aal.setPathInfo(pathInfo);
149 return new PropertyLocator(key);
155 public static Locator<URI> create(final String name, final String version) throws LocatorException {
156 return locatorCreator.create(name, version);
159 public interface LocatorCreator {
160 public AbsAAFLocator<?> create(String key, String version) throws LocatorException;
161 public void setSelf(String hostname, int port);
164 protected static String nameFromLocatorURI(URI locatorURI) {
165 String[] path = Split.split('/', locatorURI.getPath());
166 if(path.length>2 && "locate".equals(path[1])) {
169 return locatorURI.toString();
174 * Setting "self" excludes this service from the list. Critical for contacting peers.
176 public void setSelf(final String hostname, final int port) {
182 public static void setCreatorSelf(final String hostname, final int port) {
183 if(locatorCreator!=null) {
184 locatorCreator.setSelf(hostname,port);
188 protected final synchronized void replace(List<EP> list) {
193 * Call _refresh as needed during calls, but actual refresh will not occur if there
194 * are existing entities or if it has been called in the last 10 (settable) seconds.
195 * Timed Refreshes happen by Scheduled Thread
197 private final boolean _refresh() {
199 long now=System.currentTimeMillis();
202 synchronized(epList) {
204 earliest = now + refreshWait; // call only up to 10 seconds.
207 access.log(Level.ERROR, "Must wait at least " + refreshWait/1000 + " seconds for Locator Refresh");
213 private boolean noEntries() {
214 return epList.size()<=0;
218 public URI get(Item item) throws LocatorException {
221 } else if(item instanceof AAFLItem) {
222 return getURI(((AAFLItem)item).uri);
224 throw new LocatorException(item.getClass().getName() + " does not belong to AAFLocator");
229 public boolean hasItems() {
230 boolean isEmpty = epList.isEmpty();
232 for(Iterator<EP> iter = epList.iterator(); iter.hasNext(); ) {
240 if(_refresh()) { // is refreshed... check again
241 isEmpty = epList.isEmpty();
247 public void invalidate(Item item) throws LocatorException {
249 if(item instanceof AAFLItem) {
250 AAFLItem ali =(AAFLItem)item;
252 synchronized(epList) {
256 ali.iter = getIterator(); // for next guy... fresh iterator
258 throw new LocatorException(item.getClass().getName() + " does not belong to AAFLocator");
264 public Item best() throws LocatorException {
266 throw new LocatorException("No Entries found" + (pathInfo==null?"":(" for " + pathInfo)));
268 List<EP> lep = new ArrayList<EP>();
270 // Note: Deque is sorted on the way by closest distance
271 Iterator<EP> iter = getIterator();
273 while(iter.hasNext()) {
280 if(Math.abs(ep.distance-first.distance)<.1) { // allow for nearby/precision issues.
292 return new AAFLItem(iter,first);
294 int i = Math.abs(sr.nextInt())%lep.size();
298 return new AAFLItem(iter,lep.get(i));
304 private Iterator<EP> getIterator() {
305 Object[] epa = epList.toArray();
308 epa = epList.toArray();
310 return new EPIterator(epa, epList);
313 public class EPIterator implements Iterator<EP> {
314 private final Object[] epa;
315 private final List<EP> epList;
318 public EPIterator(Object[] epa, List<EP> epList) {
320 this.epList = epList;
321 idx = epa.length>0?0:-1;
325 public boolean hasNext() {
330 while(idx<epa.length) {
331 if((obj=epa[idx])==null || !((EP)obj).valid) {
337 return idx<epa.length;
343 return (EP)epa[idx++];
347 public void remove() {
348 if(idx>=0 && idx<epa.length) {
349 synchronized(epList) {
350 epList.remove(epa[idx]);
357 public Item first() {
358 Iterator<EP> iter = getIterator();
359 EP ep = AAFLItem.next(iter);
363 return new AAFLItem(iter,ep);
367 public Item next(Item prev) throws LocatorException {
369 StringBuilder sb = new StringBuilder("Locator Item passed in next(item) is null.");
371 for(StackTraceElement st : Thread.currentThread().getStackTrace()) {
373 sb.append(st.toString());
375 sb.append("\n\t...");
379 access.log(Level.ERROR, sb);
381 if(prev instanceof AAFLItem) {
382 AAFLItem ali = (AAFLItem)prev;
383 EP ep = AAFLItem.next(ali.iter);
385 return new AAFLItem(ali.iter,ep);
388 throw new LocatorException(prev.getClass().getName() + " does not belong to AAFLocator");
394 protected static class AAFLItem implements Item {
395 private Iterator<EP> iter;
399 public AAFLItem(Iterator<EP> iter, EP ep) {
405 private static EP next(Iterator<EP> iter) {
407 while(iter.hasNext() && (ep==null || !ep.valid)) {
413 public String toString() {
414 return ep==null?"Locator Item Invalid":ep.toString();
418 protected static class EP implements Comparable<EP> {
420 public final double distance;
421 private boolean valid;
423 public EP(final Endpoint ep, double latitude, double longitude) throws URISyntaxException {
424 uri = new URI(ep.getProtocol(),null,ep.getHostname(),ep.getPort(),null,null,null);
425 distance = GreatCircle.calc(latitude, longitude, ep.getLatitude(), ep.getLongitude());
429 public void invalid() {
434 public int compareTo(EP o) {
435 if(distance<o.distance) {
437 } else if(distance==o.distance) {
445 public String toString() {
446 return distance + ": " + uri + (valid?" valid":" invalidate");
451 * @see org.onap.aaf.cadi.Locator#destroy()
454 public void destroy() {
459 public String toString() {
460 return "AAFLocator for " + name + " on " + getURI();
463 public AbsAAFLocator<TRANS> setPathInfo(String pathInfo) {
464 this.pathInfo = pathInfo;
469 public AbsAAFLocator<TRANS> setQuery(String query) {
475 public AbsAAFLocator<TRANS> setFragment(String fragment) {
476 this.fragment = fragment;
481 // Core URI, for reporting purposes
482 protected abstract URI getURI();
484 protected URI getURI(URI rv) throws LocatorException {
487 return new URI(rv.getScheme(),rv.getUserInfo(),rv.getHost(),rv.getPort(),pathInfo,query,fragment);
488 } catch (URISyntaxException e) {
489 throw new LocatorException("Error coping URL");