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