8e3138afd1b56fb65b4a246f84ccce3ae7b6397f
[aaf/authz.git] / cadi / client / src / main / java / org / onap / aaf / cadi / http / HMangr.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.http;
23
24 import java.net.ConnectException;
25 import java.net.HttpURLConnection;
26 import java.net.SocketException;
27 import java.net.URI;
28 import java.net.URISyntaxException;
29
30 import javax.net.ssl.SSLHandshakeException;
31
32 import org.onap.aaf.cadi.Access;
33 import org.onap.aaf.cadi.CadiException;
34 import org.onap.aaf.cadi.Locator;
35 import org.onap.aaf.cadi.LocatorException;
36 import org.onap.aaf.cadi.SecuritySetter;
37 import org.onap.aaf.cadi.Access.Level;
38 import org.onap.aaf.cadi.Locator.Item;
39 import org.onap.aaf.cadi.client.Rcli;
40 import org.onap.aaf.cadi.client.Retryable;
41 import org.onap.aaf.misc.env.APIException;
42
43 public class HMangr {
44     private String apiVersion;
45     private int readTimeout, connectionTimeout;
46     public final Locator<URI> loc;
47     private Access access;
48     
49     public HMangr(Access access, Locator<URI> loc) throws LocatorException {
50         readTimeout = 10000;
51         connectionTimeout=3000;
52         if (loc ==  null) {
53             throw new LocatorException("Null Locator passed");
54         }
55         this.loc = loc;
56         this.access = access;
57     }
58
59     /**
60      * Reuse the same service.  This is helpful for multiple calls that change service side cached data so that 
61      * there is not a speed issue.
62      * 
63      * If the service goes down, another service will be substituted, if available.
64      * 
65      * @param access
66      * @param loc
67      * @param ss
68      * @param item
69      * @param retryable
70      * @return
71      * @throws URISyntaxException 
72      * @throws Exception
73      */
74     public<RET> RET same(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable) throws APIException, CadiException, LocatorException {
75         RET ret = null;
76         boolean retry = true;
77         Rcli<HttpURLConnection> client = retryable.lastClient();
78         try {
79             do {
80                 Item item;
81                 // if no previous state, get the best
82                 if (retryable.item()==null) {
83                     item = loc.best();
84                     if (item==null) {
85                         throw new LocatorException("No Services Found for " + loc);
86                     }
87                     retryable.item(item);
88                     retryable.lastClient = null;
89                 }
90                 if (client==null) {
91                     item = retryable.item();
92                     URI uri=loc.get(item);
93                     if (uri==null) {
94                         loc.invalidate(retryable.item());
95                         if (loc.hasItems()) {
96                             retryable.item(loc.next(retryable.item()));
97                             continue;
98                         } else {
99                             throw new LocatorException("No clients available for " + loc.toString());
100                         }
101                     }
102                     client = new HRcli(this, uri,item,ss)
103                         .connectionTimeout(connectionTimeout)
104                         .readTimeout(readTimeout)
105                         .apiVersion(apiVersion);
106                 } else {
107                     client.setSecuritySetter(ss);
108                 }
109                 
110                 retry = false;
111                 try {
112                     ret = retryable.code(client);
113                 } catch (APIException | CadiException e) {
114                     item = retryable.item();
115                     loc.invalidate(item);
116                     retryable.item(loc.next(item));
117                     try {
118                         Throwable ec = e.getCause();
119                         if (ec instanceof java.net.ConnectException) {
120                             if (client!=null && loc.hasItems()) { 
121                                 access.log(Level.WARN,"Connection refused, trying next available service");
122                                 retry = true;
123                             } else {
124                                 throw new CadiException("Connection refused, no more services to try");
125                             }
126                         } else if (ec instanceof java.net.SocketException) {
127                             if (client!=null && loc.hasItems()) { 
128                                 access.log(Level.WARN,"Socket prematurely closed, trying next available service");
129                                 retry = true;
130                             } else {
131                                 throw new CadiException("Socket prematurely closed, no more services to try");
132                             }
133                         } else if (ec instanceof SocketException) {
134                             if ("java.net.SocketException: Connection reset".equals(ec.getMessage())) {
135                                 access.log(Level.ERROR, ec.getMessage(), " can mean Certificate Expiration or TLS Protocol issues");
136                             }
137                             retryable.item(null);
138                             throw e;
139                         } else {
140                             retryable.item(null);
141                             throw e;
142                         }
143                     } finally {
144                         client = null;
145                     }
146                 } catch (ConnectException e) {
147                     item = retryable.item();
148                     loc.invalidate(item);
149                     retryable.item(loc.next(item));
150                 }
151             } while (retry);
152         } finally {
153             retryable.lastClient = client;
154         }
155         return ret;
156     }
157     
158     
159     public<RET> RET best(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable) throws LocatorException, CadiException, APIException {
160         retryable.item(loc.best());
161         return same(ss,retryable);
162     }
163     public<RET> RET all(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable) throws LocatorException, CadiException, APIException {
164         return oneOf(ss,retryable,true,null);
165     }
166
167     public<RET> RET all(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable,boolean notify) throws LocatorException, CadiException, APIException {
168         return oneOf(ss,retryable,notify,null);
169     }
170     
171     public<RET> RET oneOf(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable,boolean notify,String host) throws LocatorException, CadiException, APIException {
172         RET ret = null;
173         // make sure we have all current references:
174         loc.refresh();
175         for (Item li=loc.first();li!=null;li=loc.next(li)) {
176             URI uri=loc.get(li);
177             if (host!=null && !host.equals(uri.getHost())) {
178                 break;
179             }
180             try {
181                 ret = retryable.code(new HRcli(this,uri,li,ss));
182                 access.log(Level.DEBUG,"Success calling",uri,"during call to all services");
183             } catch (APIException | CadiException e) {
184                 Throwable t = e.getCause();
185                 if (t!=null && t instanceof ConnectException) {
186                     loc.invalidate(li);
187                     access.log(Level.ERROR,"Connection to",uri,"refused during call to all services");
188                 } else if (t instanceof SSLHandshakeException) {
189                     access.log(Level.ERROR,t.getMessage());
190                     loc.invalidate(li);
191                 } else if (t instanceof SocketException) {
192                     if ("java.net.SocketException: Connection reset".equals(t.getMessage())) {
193                         access.log(Level.ERROR, t.getMessage(), " can mean Certificate Expiration or TLS Protocol issues");
194                     }
195                     retryable.item(null);
196                     throw e;
197                 } else {
198                     throw e;
199                 }
200             } catch (ConnectException e) {
201                 loc.invalidate(li);
202                 access.log(Level.ERROR,"Connection to",uri,"refused during call to all services");
203             }
204         }
205             
206         if (ret == null && notify) 
207             throw new LocatorException("No available clients to call");
208         return ret;
209     }
210     
211
212     public void close() {
213         // TODO Anything here?
214     }
215
216     public HMangr readTimeout(int timeout) {
217         this.readTimeout = timeout;
218         return this;
219     }
220
221     public int readTimeout() {
222         return readTimeout;
223     }
224     
225     public void connectionTimeout(int t) {
226         connectionTimeout = t;
227     }
228
229     public int connectionTimeout() {
230         return connectionTimeout;
231     }
232
233     public HMangr apiVersion(String version) {
234         apiVersion = version;
235         return this;
236     }
237
238     public String apiVersion() {
239         return apiVersion;
240     }
241
242 }