diff options
Diffstat (limited to 'cadi/client')
3 files changed, 385 insertions, 235 deletions
diff --git a/cadi/client/src/main/java/org/onap/aaf/cadi/locator/HotPeerLocator.java b/cadi/client/src/main/java/org/onap/aaf/cadi/locator/HotPeerLocator.java index 17f9bafb..fd8e99dc 100644 --- a/cadi/client/src/main/java/org/onap/aaf/cadi/locator/HotPeerLocator.java +++ b/cadi/client/src/main/java/org/onap/aaf/cadi/locator/HotPeerLocator.java @@ -7,9 +7,9 @@ * 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. @@ -29,274 +29,273 @@ import org.onap.aaf.cadi.routing.GreatCircle; import org.onap.aaf.misc.env.util.Split; /** - * This Locator is to handle Hot Peer load protection, when the Servers are + * This Locator is to handle Hot Peer load protection, when the Servers are * 1) Static * 2) Well known client URL - * + * * The intention is to change traffic over to the Hot Peer, if a server goes down, and reinstate * when it is back up. - * + * * Example of this kind of Service is a MS Certificate Server - * + * * @author Jonathan * * @param <CLIENT> */ public abstract class HotPeerLocator<CLIENT> implements Locator<CLIENT> { - private final String[] urlstrs; - private final CLIENT[] clients; - private final long[] failures; - private final double[] distances; - private int preferred; - private long invalidateTime; - private Thread refreshThread; - protected Access access; + private final String[] urlstrs; + private final CLIENT[] clients; + private final long[] failures; + private final double[] distances; + private int preferred; + private long invalidateTime; + private Thread refreshThread; + protected Access access; - /** - * Construct: Expect one or more Strings in the form: - * 192.555.112.223:39/38.88087/-77.30122 - * separated by commas - * - * @param trans - * @param urlstr - * @param invalidateTime - * @param localLatitude - * @param localLongitude - * @throws LocatorException - */ - @SuppressWarnings("unchecked") - protected HotPeerLocator(Access access, final String urlstr, final long invalidateTime, final String localLatitude, final String localLongitude) throws LocatorException { - this.access = access; - urlstrs = Split.split(',', urlstr); - clients = (CLIENT[])new Object[urlstrs.length]; - failures = new long[urlstrs.length]; - distances= new double[urlstrs.length]; - this.invalidateTime = invalidateTime; - - double distance = Double.MAX_VALUE; - for(int i=0;i<urlstrs.length;++i) { - String[] info = Split.split('/', urlstrs[i]); - if(info.length<3) { - throw new LocatorException("Configuration needs LAT and LONG, i.e. ip:port/lat/long"); - } - try { - clients[i] = _newClient(urlstrs[i]); - failures[i] = 0L; - } catch(LocatorException le) { - failures[i] = System.currentTimeMillis()+invalidateTime; - } - - double d = GreatCircle.calc(info[1],info[2],localLatitude,localLongitude); - distances[i]=d; - - // find preferred server - if(d<distance) { - preferred = i; - distance=d; - } - } - - access.printf(Level.INIT,"Preferred Client is %s",urlstrs[preferred]); - for(int i=0;i<urlstrs.length;++i) { - if(i!=preferred) { - access.printf(Level.INIT,"Alternate Client is %s",urlstrs[i]); - } - } - } - - protected abstract CLIENT _newClient(String hostInfo) throws LocatorException; - /** - * If client can reconnect, then return. Otherwise, destroy and return null; - * @param client - * @return - * @throws LocatorException - */ - protected abstract CLIENT _invalidate(CLIENT client); - - protected abstract void _destroy(CLIENT client); - - @Override - public Item best() throws LocatorException { - if(failures[preferred]==0L) { - return new HPItem(preferred); - } else { - long now = System.currentTimeMillis(); - double d = Double.MAX_VALUE; - int best = -1; - boolean tickle = false; - // try for best existing client - for(int i=0;i<urlstrs.length;++i) { - if(failures[i]<now && distances[i]<d) { - if(clients[i]!=null) { - best = i; - break; - } else { - tickle = true; // There's some failed clients which can be restored - } + /** + * Construct: Expect one or more Strings in the form: + * 192.555.112.223:39/38.88087/-77.30122 + * separated by commas + * + * @param trans + * @param urlstr + * @param invalidateTime + * @param localLatitude + * @param localLongitude + * @throws LocatorException + */ + @SuppressWarnings("unchecked") + protected HotPeerLocator(Access access, final String urlstr, final long invalidateTime, final String localLatitude, final String localLongitude) throws LocatorException { + this.access = access; + urlstrs = Split.split(',', urlstr); + clients = (CLIENT[])new Object[urlstrs.length]; + failures = new long[urlstrs.length]; + distances= new double[urlstrs.length]; + this.invalidateTime = invalidateTime; + + double distance = Double.MAX_VALUE; + for(int i=0;i<urlstrs.length;++i) { + String[] info = Split.split('/', urlstrs[i]); + if(info.length<3) { + throw new LocatorException("Configuration needs LAT and LONG, i.e. ip:port/lat/long"); + } + try { + clients[i] = _newClient(urlstrs[i]); + failures[i] = 0L; + } catch(LocatorException le) { + failures[i] = System.currentTimeMillis()+invalidateTime; + } + + double d = GreatCircle.calc(info[1],info[2],localLatitude,localLongitude); + distances[i]=d; + + // find preferred server + if(d<distance) { + preferred = i; + distance=d; + } + } + + access.printf(Level.INIT,"Preferred Client is %s",urlstrs[preferred]); + for(int i=0;i<urlstrs.length;++i) { + if(i!=preferred) { + access.printf(Level.INIT,"Alternate Client is %s",urlstrs[i]); + } + } + } + + protected abstract CLIENT _newClient(String hostInfo) throws LocatorException; + /** + * If client can reconnect, then return. Otherwise, destroy and return null; + * @param client + * @return + * @throws LocatorException + */ + protected abstract CLIENT _invalidate(CLIENT client); + + protected abstract void _destroy(CLIENT client); + + @Override + public Item best() throws LocatorException { + if(failures[preferred]==0L) { + return new HPItem(preferred); + } else { + long now = System.currentTimeMillis(); + double d = Double.MAX_VALUE; + int best = -1; + boolean tickle = false; + // try for best existing client + for(int i=0;i<urlstrs.length;++i) { + if(failures[i]<now && distances[i]<d) { + if(clients[i]!=null) { + best = i; + break; + } else { + tickle = true; // There's some failed clients which can be restored } } - if(best<0 && tickle) { - tickle=false; - if(refresh()) { - // try again - for(int i=0;i<urlstrs.length;++i) { - if(failures[i]==0L && distances[i]<d) { - if(clients[i]!=null) { - best = i; - break; - } + } + if(best<0 && tickle) { + tickle=false; + if(refresh()) { + // try again + for(int i=0;i<urlstrs.length;++i) { + if(failures[i]==0L && distances[i]<d) { + if(clients[i]!=null) { + best = i; + break; } } } } - - /* - * If a valid client is available, but there are some that can refresh, return the client immediately - * but start a Thread to do the background Client setup. - */ - if(tickle) { - synchronized(clients) { - if(refreshThread==null) { - refreshThread = new Thread(new Runnable(){ - @Override - public void run() { - refresh(); - refreshThread = null; - } - }); - refreshThread.setDaemon(true); - refreshThread.start(); - } - } - } - - if(best<0) { - throw new LocatorException("No Clients available"); - } - - - return new HPItem(best); } - } - - @Override - public CLIENT get(Item item) throws LocatorException { - HPItem hpi = (HPItem)item; - CLIENT c = clients[hpi.idx]; - if(c==null) { - if(failures[hpi.idx]>System.currentTimeMillis()) { - throw new LocatorException("Client requested is invalid"); - } else { - synchronized(clients) { - c = _newClient(urlstrs[hpi.idx]); - failures[hpi.idx]=0L; + /* + * If a valid client is available, but there are some that can refresh, return the client immediately + * but start a Thread to do the background Client setup. + */ + if(tickle) { + synchronized(clients) { + if(refreshThread==null) { + refreshThread = new Thread(new Runnable(){ + @Override + public void run() { + refresh(); + refreshThread = null; + } + }); + refreshThread.setDaemon(true); + refreshThread.start(); } } - } else if(failures[hpi.idx]>0){ - throw new LocatorException("Client requested is invalid"); } - return c; - } - - public String info(Item item) { - HPItem hpi = (HPItem)item; - if(hpi!=null && hpi.idx<urlstrs.length) { - return urlstrs[hpi.idx]; - } else { - return "Invalid Item"; + + if(best<0) { + throw new LocatorException("No Clients available"); } + + return new HPItem(best); } + } + - @Override - public boolean hasItems() { - for(int i=0;i<clients.length;++i) { - if(clients[i]!=null && failures[i]==0L) { - return true; + @Override + public CLIENT get(Item item) throws LocatorException { + HPItem hpi = (HPItem)item; + CLIENT c = clients[hpi.idx]; + if(c==null) { + if(failures[hpi.idx]>System.currentTimeMillis()) { + throw new LocatorException("Client requested is invalid"); + } else { + synchronized(clients) { + c = _newClient(urlstrs[hpi.idx]); + failures[hpi.idx]=0L; } } - return false; - } - - @Override - public synchronized void invalidate(Item item) throws LocatorException { - HPItem hpi = (HPItem)item; - failures[hpi.idx] = System.currentTimeMillis() + invalidateTime; - CLIENT c = clients[hpi.idx]; - clients[hpi.idx] = _invalidate(c); + } else if(failures[hpi.idx]>0){ + throw new LocatorException("Client requested is invalid"); } - - @Override - public Item first() throws LocatorException { - return new HPItem(0); + return c; + } + + public String info(Item item) { + HPItem hpi = (HPItem)item; + if(hpi!=null && hpi.idx<urlstrs.length) { + return urlstrs[hpi.idx]; + } else { + return "Invalid Item"; } - - @Override - public Item next(Item item) throws LocatorException { - HPItem hpi = (HPItem)item; - if(++hpi.idx>=clients.length) { - return null; + } + + @Override + public boolean hasItems() { + for(int i=0;i<clients.length;++i) { + if(clients[i]!=null && failures[i]==0L) { + return true; } - return hpi; } - - @Override - public boolean refresh() { - boolean force = !hasItems(); // If no Items at all, reset - boolean rv = true; - long now = System.currentTimeMillis(); - for(int i=0;i<clients.length;++i) { - if(failures[i]>0L && (failures[i]<now || force)) { // retry - try { - synchronized(clients) { - if(clients[i]==null) { - clients[i]=_newClient(urlstrs[i]); - } - failures[i]=0L; + return false; + } + + @Override + public synchronized void invalidate(Item item) throws LocatorException { + HPItem hpi = (HPItem)item; + failures[hpi.idx] = System.currentTimeMillis() + invalidateTime; + CLIENT c = clients[hpi.idx]; + clients[hpi.idx] = _invalidate(c); + } + + @Override + public Item first() throws LocatorException { + return new HPItem(0); + } + + @Override + public Item next(Item item) throws LocatorException { + HPItem hpi = (HPItem)item; + if(++hpi.idx>=clients.length) { + return null; + } + return hpi; + } + + @Override + public boolean refresh() { + boolean force = !hasItems(); // If no Items at all, reset + boolean rv = true; + long now = System.currentTimeMillis(); + for(int i=0;i<clients.length;++i) { + if(failures[i]>0L && (failures[i]<now || force)) { // retry + try { + synchronized(clients) { + if(clients[i]==null) { + clients[i]=_newClient(urlstrs[i]); } - } catch (LocatorException e) { - failures[i]=now+invalidateTime; - rv = false; + failures[i]=0L; } + } catch (LocatorException e) { + failures[i]=now+invalidateTime; + rv = false; } } - return rv; } - - @Override - public void destroy() { - for(int i=0;i<clients.length;++i) { - if(clients[i]!=null) { - _destroy(clients[i]); - clients[i] = null; - } + return rv; + } + + @Override + public void destroy() { + for(int i=0;i<clients.length;++i) { + if(clients[i]!=null) { + _destroy(clients[i]); + clients[i] = null; } } + } - private static class HPItem implements Item { - private int idx; + private static class HPItem implements Item { + private int idx; - public HPItem(int i) { - idx = i; - } + public HPItem(int i) { + idx = i; } - + } - /* - * Convenience Functions - */ - public CLIENT bestClient() throws LocatorException { - return get(best()); - } - public boolean invalidate(CLIENT client) throws LocatorException { - for(int i=0;i<clients.length;++i) { - if(clients[i]==client) { // yes, "==" is appropriate here.. Comparing Java Object Reference - invalidate(new HPItem(i)); - return true; - } + /* + * Convenience Functions + */ + public CLIENT bestClient() throws LocatorException { + return get(best()); + } + + public boolean invalidate(CLIENT client) throws LocatorException { + for(int i=0;i<clients.length;++i) { + if(clients[i]==client) { // yes, "==" is appropriate here.. Comparing Java Object Reference + invalidate(new HPItem(i)); + return true; } - return false; } + return false; + } - }
\ No newline at end of file +}
\ No newline at end of file diff --git a/cadi/client/src/test/java/org/onap/aaf/cadi/locator/test/JU_DNSLocator.java b/cadi/client/src/test/java/org/onap/aaf/cadi/locator/test/JU_DNSLocator.java index d9f75ff1..20e31347 100644 --- a/cadi/client/src/test/java/org/onap/aaf/cadi/locator/test/JU_DNSLocator.java +++ b/cadi/client/src/test/java/org/onap/aaf/cadi/locator/test/JU_DNSLocator.java @@ -42,14 +42,14 @@ public class JU_DNSLocator { // TODO: Actually test this class - Ian DNSLocator dl = new DNSLocator(new PropAccess(), "https", "aaf.it.att.com","8150-8152"); - try { - Item item = dl.best(); - URI uri = dl.get(item); - URL url = uri.toURL(); - URLConnection conn = url.openConnection(); - conn.connect(); - } catch (Exception e) { - } +// try { +// Item item = dl.best(); +// URI uri = dl.get(item); +// URL url = uri.toURL(); +// URLConnection conn = url.openConnection(); +// conn.connect(); +// } catch (Exception e) { +// } } } diff --git a/cadi/client/src/test/java/org/onap/aaf/cadi/locator/test/JU_HClientHotPeerLocator.java b/cadi/client/src/test/java/org/onap/aaf/cadi/locator/test/JU_HClientHotPeerLocator.java new file mode 100644 index 00000000..4b008c2c --- /dev/null +++ b/cadi/client/src/test/java/org/onap/aaf/cadi/locator/test/JU_HClientHotPeerLocator.java @@ -0,0 +1,151 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 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.onap.aaf.cadi.locator.test; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; +import static org.hamcrest.CoreMatchers.*; +import org.junit.*; +import org.mockito.*; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.Locator; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.http.HClient; +import org.onap.aaf.cadi.http.HX509SS; +import org.onap.aaf.cadi.locator.HClientHotPeerLocator; + +public class JU_HClientHotPeerLocator { + + @Mock private HX509SS ssMock; + + private PropAccess access; + private ByteArrayOutputStream outStream; + + // Note: - The IP and port are irrelevant for these tests + private static final String goodURL1 = "fakeIP1:fakePort1/38/-90"; // Approx St Louis + private static final String goodURL2 = "fakeIP2:fakePort2/33/-96"; // Approx Dallas + private static final String badURL = "~%$!@#$//"; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + + outStream = new ByteArrayOutputStream(); + access = new PropAccess(new PrintStream(outStream), new String[0]); + } + + @Test + public void test() throws LocatorException { + HClientHotPeerLocator loc; + String urlStr = goodURL1 + ',' + goodURL2; + loc = new HClientHotPeerLocator(access, urlStr, 0, "38.627", "-90.199", ssMock); + assertThat(loc.hasItems(), is(true)); + + String[] messages = outStream.toString().split("\n"); + String preffered = messages[0].split(" ", 4)[3]; + String alternate = messages[1].split(" ", 4)[3]; + assertThat(preffered, is("Preferred Client is " + goodURL1)); + assertThat(alternate, is("Alternate Client is " + goodURL2)); + + HClient firstClient = loc.get(loc.first()); + HClient bestClient = loc.bestClient(); + assertThat(bestClient, is(firstClient)); + + Locator.Item item = loc.first(); + assertThat(loc.info(item), is(goodURL1)); + + item = loc.next(item); + assertThat(loc.info(item), is(goodURL2)); + + item = loc.next(item); + assertThat(item, is(nullValue())); + assertThat(loc.info(item), is("Invalid Item")); + + item = loc.first(); + loc.invalidate(item); + loc.get(item); + + loc.destroy(); + item = loc.best(); + } + + @Test(expected = LocatorException.class) + public void failuresTest() throws LocatorException { + HClientHotPeerLocator loc; + String urlStr = goodURL1 + ',' + goodURL2 + ',' + badURL; + loc = new HClientHotPeerLocator(access, urlStr, 1000000, "38.627", "-90.199", ssMock); + String[] messages = outStream.toString().split("\n"); + String preffered = messages[0].split(" ", 4)[3]; + String alternate1 = messages[1].split(" ", 4)[3]; + String alternate2 = messages[2].split(" ", 4)[3]; + assertThat(preffered, is("Preferred Client is " + badURL)); + assertThat(alternate1, is("Alternate Client is " + goodURL1)); + assertThat(alternate2, is("Alternate Client is " + goodURL2)); + + outStream.reset(); + + loc.invalidate(loc.first()); + + loc.destroy(); + Locator.Item item = loc.best(); + } + + @Test + public void hasNoItemTest() throws LocatorException { + HClientHotPeerLocator loc; + loc = new HClientHotPeerLocator(access, badURL, 0, "38.627", "-90.199", ssMock); + assertThat(loc.hasItems(), is(false)); + loc.invalidate(loc.first()); + } + + @Test(expected = LocatorException.class) + public void invalidClientTest() throws LocatorException { + @SuppressWarnings("unused") + HClientHotPeerLocator loc = new HClientHotPeerLocator(access, "InvalidClient", 0, "38.627", "-90.199", ssMock); + } + + @Test(expected = LocatorException.class) + public void coverageTest() throws LocatorException { + CoverageLocator loc; + String urlStr = goodURL1 + ',' + goodURL2; + loc = new CoverageLocator(access, urlStr, 0, "38.627", "-90.199", ssMock); + assertThat(loc._invalidate(null), is(nullValue())); + loc._destroy(null); + + loc._newClient("bad string"); + } + + private class CoverageLocator extends HClientHotPeerLocator { + public CoverageLocator(Access access, String urlstr, long invalidateTime, String localLatitude, + String localLongitude, HX509SS ss) throws LocatorException { + super(access, urlstr, invalidateTime, localLatitude, localLongitude, ss); + } + public HClient _newClient(String clientInfo) throws LocatorException { return super._newClient(clientInfo); } + public HClient _invalidate(HClient client) { return super._invalidate(client); } + public void _destroy(HClient client) { super._destroy(client); } + } +} |