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