K8s doesn't necessarily support DNS
[aaf/authz.git] / cadi / client / src / main / java / org / onap / aaf / cadi / locator / DNSLocator.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.URI;
27 import java.net.URISyntaxException;
28
29 import org.onap.aaf.cadi.Access;
30 import org.onap.aaf.cadi.Access.Level;
31 import org.onap.aaf.cadi.LocatorException;
32
33 public class DNSLocator implements SizedLocator<URI> {
34     private static enum Status {UNTRIED, OK, INVALID, SLOW};
35     private static final int CHECK_TIME = 3000;
36     
37     private String host, protocol;
38     private Access access;
39     private Host[] hosts;
40     private int startPort, endPort;
41     private String suffix;
42
43     private int size = 1; // initial, until refreshed.
44     
45     public DNSLocator(Access access, String protocol, String host, String range) {
46         this.host = host;
47         this.protocol = protocol;
48         this.access = access;
49         int dash = range.indexOf('-');
50         if (dash<0) {
51             startPort = endPort = Integer.parseInt(range);
52         } else {
53             startPort = Integer.parseInt(range.substring(0,dash));
54             endPort = Integer.parseInt(range.substring(dash + 1));
55         }
56         refresh();
57     }
58
59     public DNSLocator(Access access, String aaf_locate) throws LocatorException {
60         this.access = access;
61         if (aaf_locate==null) {
62             throw new LocatorException("Null passed into DNSLocator constructor");
63         }
64         int start, defPort;
65         if (aaf_locate.startsWith("https://")) {
66             protocol = "https";
67             start = 8; // https://
68             defPort = 443;
69         } else if (aaf_locate.startsWith("http://")) {
70             protocol = "http";
71             start = 7; // http://
72             defPort = 80;
73         } else {
74             throw new LocatorException("DNSLocator accepts only https or http protocols.  (requested URL " + aaf_locate + ')');
75         }
76         host = parseHostAndPorts(aaf_locate, start, defPort);
77         refresh();
78     }
79
80     public static DNSLocator create(Access access, String url) throws LocatorException {
81         return new DNSLocator(access, url);
82     }
83
84     @Override
85     public URI get(Item item) throws LocatorException {
86         return hosts[((DLItem)item).cnt].uri;
87     }
88
89     @Override
90     public boolean hasItems() {
91         for (Host h : hosts) {
92             if (h.status==Status.OK) {
93                 return true;
94             }
95         }
96         return false;
97     }
98
99     @Override
100     public void invalidate(Item item) {
101         DLItem di = (DLItem)item;
102         hosts[di.cnt].status = Status.INVALID;
103     }
104
105     @Override
106     public Item best() throws LocatorException {
107         // not a good "best"
108         for (int i=0;i<hosts.length;++i) {
109             switch(hosts[i].status) {
110                 case OK:
111                     return new DLItem(i);
112                 case INVALID:
113                     break;
114                 case SLOW:
115                     break;
116                 case UNTRIED:
117                     try {
118                         if (hosts[i].ia.isReachable(CHECK_TIME)) {
119                             hosts[i].status = Status.OK;
120                             return new DLItem(i);
121                         }
122                     } catch (IOException e) {
123                         throw new LocatorException(e);
124                     }
125                     break;
126                 default:
127                     break;
128             }
129         }
130         throw new LocatorException("No Available URIs for " + host);
131     }
132
133     @Override
134     public Item first() throws LocatorException {
135         return new DLItem(0);
136     }
137
138     @Override
139     public Item next(Item item) throws LocatorException {
140         DLItem di = (DLItem)item;
141         if (++di.cnt<hosts.length) {
142             return di;
143         } else {
144             return null;
145         }
146     }
147
148     @Override
149     public boolean refresh() {
150         try {
151             InetAddress[] ias = InetAddress.getAllByName(host);
152             Host[] temp = new Host[ias.length * (1 + endPort - startPort)];
153             int cnt = -1;
154             for (int j=startPort; j<=endPort; ++j) {
155                 for (int i=0;i<ias.length;++i) {
156                     temp[++cnt] = new Host(ias[i], j, suffix);
157                 }
158             }
159             hosts = temp;
160             size = temp.length * (endPort-startPort+1);
161             return true;
162         } catch (Exception e) {
163             access.log(Level.ERROR, e);
164         }
165         return false;
166     }
167     
168     private String parseHostAndPorts(String aaf_locate, int _start, int defaultPort) throws LocatorException {
169         int slash, start;
170         int colon = aaf_locate.indexOf(':',_start);
171         if (colon > 0) {
172             host = aaf_locate.substring(_start,colon);
173             start = colon + 1;
174             int left = aaf_locate.indexOf('[', start);
175             if (left > 0) {
176                 int right = aaf_locate.indexOf(']', left + 1);
177                 if (right < 0) {
178                     throw new LocatorException("Missing closing bracket in DNSLocator constructor.  (requested URL " + aaf_locate + ')');
179                 } else if (right == (left + 1)) {
180                     throw new LocatorException("Missing ports in brackets in DNSLocator constructor.  (requested URL " + aaf_locate + ')');
181                 }
182                 int dash = aaf_locate.indexOf('-', left + 1);
183                 if (dash == (right - 1) || dash == (left + 1)) {
184                     throw new LocatorException("Missing ports in brackets in DNSLocator constructor.  (requested URL " + aaf_locate + ')');
185                 }
186                 if (dash < 0) {
187                     startPort = endPort = Integer.parseInt(aaf_locate.substring(left + 1, right));
188                 } else {
189                     startPort = Integer.parseInt(aaf_locate.substring(left + 1, dash));
190                     endPort = Integer.parseInt(aaf_locate.substring(dash + 1, right));
191                 }
192                 slash = aaf_locate.indexOf('/', start);
193                 if(slash>=0) {
194                     suffix = aaf_locate.substring(slash);
195                 }
196                 
197             } else {
198                 slash = aaf_locate.indexOf('/', start);
199                 if (slash == start) {
200                     throw new LocatorException("Missing port before '/' in DNSLocator constructor.  (requested URL " + aaf_locate + ')');
201                 }
202                 if (slash < 0) {
203                     startPort = endPort = Integer.parseInt(aaf_locate.substring(start));
204                 } else {
205                     startPort = endPort = Integer.parseInt(aaf_locate.substring(start, slash));
206                     suffix = aaf_locate.substring(slash);
207                 }
208             }
209         } else {
210             slash = aaf_locate.indexOf('/', _start);
211             host = slash<_start?aaf_locate.substring(_start):aaf_locate.substring(_start,slash);
212             startPort = endPort = defaultPort;
213         }
214         
215         return host;
216     }
217
218     private class Host {
219         private URI uri;
220         private InetAddress ia;
221         private Status status;
222         
223         public Host(InetAddress inetAddress, int port, String suffix) throws URISyntaxException {
224             ia = inetAddress;
225             uri = new URI(protocol,null,inetAddress.getCanonicalHostName(),port,suffix,null,null);
226             status = Status.UNTRIED;
227         }
228         
229         public String toString() {
230             return uri.toString() + " - " + status.name();
231         }
232     }
233     
234     private class DLItem implements Item {
235         public DLItem(int i) {
236             cnt = i;
237         }
238
239         private int cnt;
240     }
241     
242     public void destroy() {}
243
244     public int size() {
245         return size;
246     }
247 }