833434f722efdaec52208cc1fd82a7c0d42fd91d
[aaf/cadi.git] / client / src / main / java / org / onap / aaf / cadi / http / HMangr.java
1 /*******************************************************************************\r
2  * ============LICENSE_START====================================================\r
3  * * org.onap.aaf\r
4  * * ===========================================================================\r
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
6  * * ===========================================================================\r
7  * * Licensed under the Apache License, Version 2.0 (the "License");\r
8  * * you may not use this file except in compliance with the License.\r
9  * * You may obtain a copy of the License at\r
10  * * \r
11  *  *      http://www.apache.org/licenses/LICENSE-2.0\r
12  * * \r
13  *  * Unless required by applicable law or agreed to in writing, software\r
14  * * distributed under the License is distributed on an "AS IS" BASIS,\r
15  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  * * See the License for the specific language governing permissions and\r
17  * * limitations under the License.\r
18  * * ============LICENSE_END====================================================\r
19  * *\r
20  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
21  * *\r
22  ******************************************************************************/\r
23 package org.onap.aaf.cadi.http;\r
24 \r
25 import java.net.ConnectException;\r
26 import java.net.HttpURLConnection;\r
27 import java.net.SocketException;\r
28 import java.net.URI;\r
29 import java.net.URISyntaxException;\r
30 \r
31 import javax.net.ssl.SSLHandshakeException;\r
32 \r
33 import org.onap.aaf.cadi.Access;\r
34 import org.onap.aaf.cadi.CadiException;\r
35 import org.onap.aaf.cadi.Locator;\r
36 import org.onap.aaf.cadi.LocatorException;\r
37 import org.onap.aaf.cadi.SecuritySetter;\r
38 import org.onap.aaf.cadi.Access.Level;\r
39 import org.onap.aaf.cadi.Locator.Item;\r
40 import org.onap.aaf.cadi.client.Rcli;\r
41 import org.onap.aaf.cadi.client.Retryable;\r
42 \r
43 import org.onap.aaf.inno.env.APIException;\r
44 \r
45 public class HMangr {\r
46         private String apiVersion;\r
47         private int readTimeout, connectionTimeout;\r
48         public final Locator<URI> loc;\r
49         private Access access;\r
50         \r
51         public HMangr(Access access, Locator<URI> loc) {\r
52                 readTimeout = 10000;\r
53                 connectionTimeout=3000;\r
54                 this.loc = loc;\r
55                 this.access = access;\r
56         }\r
57 \r
58         /**\r
59          * Reuse the same service.  This is helpful for multiple calls that change service side cached data so that \r
60          * there is not a speed issue.\r
61          * \r
62          * If the service goes down, another service will be substituted, if available.\r
63          * \r
64          * @param access\r
65          * @param loc\r
66          * @param ss\r
67          * @param item\r
68          * @param retryable\r
69          * @return\r
70          * @throws URISyntaxException \r
71          * @throws Exception\r
72          */\r
73         public<RET> RET same(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable) throws APIException, CadiException, LocatorException {\r
74                 RET ret = null;\r
75                 boolean retry = true;\r
76                 int retries = 0;\r
77                 Rcli<HttpURLConnection> client = retryable.lastClient();\r
78                 try {\r
79                         do {\r
80                                 // if no previous state, get the best\r
81                                 if(retryable.item()==null) {\r
82                                         retryable.item(loc.best());\r
83                                         retryable.lastClient = null;\r
84                                 }\r
85                                 if(client==null) {\r
86                                         Item item = retryable.item();\r
87                                         URI uri=loc.get(item);\r
88                                         if(uri==null) {\r
89                                                 loc.invalidate(retryable.item());\r
90                                                 if(loc.hasItems()) {\r
91                                                         retryable.item(loc.next(retryable.item()));\r
92                                                         continue;\r
93                                                 } else {\r
94                                                         throw new LocatorException("No clients available for " + loc.toString());\r
95                                                 }\r
96                                         }\r
97                                         client = new HRcli(this, uri,item,ss)\r
98                                                 .connectionTimeout(connectionTimeout)\r
99                                                 .readTimeout(readTimeout)\r
100                                                 .apiVersion(apiVersion);\r
101                                 } else {\r
102                                         client.setSecuritySetter(ss);\r
103                                 }\r
104                                 \r
105                                 retry = false;\r
106                                 try {\r
107                                         ret = retryable.code(client);\r
108                                 } catch (APIException | CadiException e) {\r
109                                         Item item = retryable.item();\r
110                                         loc.invalidate(item);\r
111                                         retryable.item(loc.next(item));\r
112                                         try {\r
113                                                 Throwable ec = e.getCause();\r
114                                                 if(ec instanceof java.net.ConnectException) {\r
115                                                         if(client!=null && ++retries<2) { \r
116                                                                 access.log(Level.WARN,"Connection refused, trying next available service");\r
117                                                                 retry = true;\r
118                                                         } else {\r
119                                                                 throw new CadiException("Connection refused, no more available connections to try");\r
120                                                         }\r
121                                                 } else if(ec instanceof SSLHandshakeException) {\r
122                                                         retryable.item(null);\r
123                                                         throw e;\r
124                                                 } else if(ec instanceof SocketException) {\r
125                                                         if("java.net.SocketException: Connection reset".equals(ec.getMessage())) {\r
126                                                                 access.log(Level.ERROR, ec.getMessage(), " can mean Certificate Expiration or TLS Protocol issues");\r
127                                                         }\r
128                                                         retryable.item(null);\r
129                                                         throw e;\r
130                                                 } else {\r
131                                                         retryable.item(null);\r
132                                                         throw e;\r
133                                                 }\r
134                                         } finally {\r
135                                                 client = null;\r
136                                         }\r
137                                 } catch (ConnectException e) {\r
138                                         Item item = retryable.item();\r
139                                         loc.invalidate(item);\r
140                                         retryable.item(loc.next(item));\r
141                                 }\r
142                         } while(retry);\r
143                 } finally {\r
144                         retryable.lastClient = client;\r
145                 }\r
146                 return ret;\r
147         }\r
148         \r
149         \r
150         public<RET> RET best(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable) throws LocatorException, CadiException, APIException {\r
151                 if(loc==null) {\r
152                         throw new LocatorException("No Locator Configured");\r
153                 }\r
154                 retryable.item(loc.best());\r
155                 return same(ss,retryable);\r
156         }\r
157         public<RET> RET all(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable) throws LocatorException, CadiException, APIException {\r
158                 return oneOf(ss,retryable,true,null);\r
159         }\r
160 \r
161         public<RET> RET all(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable,boolean notify) throws LocatorException, CadiException, APIException {\r
162                 return oneOf(ss,retryable,notify,null);\r
163         }\r
164         \r
165         public<RET> RET oneOf(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable,boolean notify,String host) throws LocatorException, CadiException, APIException {\r
166                 RET ret = null;\r
167                 // make sure we have all current references:\r
168                 loc.refresh();\r
169                 for(Item li=loc.first();li!=null;li=loc.next(li)) {\r
170                         URI uri=loc.get(li);\r
171                         if(host!=null && !host.equals(uri.getHost())) {\r
172                                 break;\r
173                         }\r
174                         try {\r
175                                 ret = retryable.code(new HRcli(this,uri,li,ss));\r
176                                 access.log(Level.DEBUG,"Success calling",uri,"during call to all services");\r
177                         } catch (APIException | CadiException e) {\r
178                                 Throwable t = e.getCause();\r
179                                 if(t!=null && t instanceof ConnectException) {\r
180                                         loc.invalidate(li);\r
181                                         access.log(Level.ERROR,"Connection to",uri,"refused during call to all services");\r
182                                 } else if(t instanceof SSLHandshakeException) {\r
183                                         access.log(Level.ERROR,t.getMessage());\r
184                                         loc.invalidate(li);\r
185                                 } else if(t instanceof SocketException) {\r
186                                         if("java.net.SocketException: Connection reset".equals(t.getMessage())) {\r
187                                                 access.log(Level.ERROR, t.getMessage(), " can mean Certificate Expiration or TLS Protocol issues");\r
188                                         }\r
189                                         retryable.item(null);\r
190                                         throw e;\r
191                                 } else {\r
192                                         throw e;\r
193                                 }\r
194                         } catch (ConnectException e) {\r
195                                 loc.invalidate(li);\r
196                                 access.log(Level.ERROR,"Connection to",uri,"refused during call to all services");\r
197                         }\r
198                 }\r
199                         \r
200                 if(ret == null && notify) \r
201                         throw new LocatorException("No available clients to call");\r
202                 return ret;\r
203         }\r
204         \r
205 \r
206         public void close() {\r
207                 // TODO Anything here?\r
208         }\r
209 \r
210         public HMangr readTimeout(int timeout) {\r
211                 this.readTimeout = timeout;\r
212                 return this;\r
213         }\r
214 \r
215         public int readTimeout() {\r
216                 return readTimeout;\r
217         }\r
218         \r
219         public void connectionTimeout(int t) {\r
220                 connectionTimeout = t;\r
221         }\r
222 \r
223         public int connectionTimout() {\r
224                 return connectionTimeout;\r
225         }\r
226 \r
227         public HMangr apiVersion(String version) {\r
228                 apiVersion = version;\r
229                 return this;\r
230         }\r
231 \r
232         public String apiVersion() {\r
233                 return apiVersion;\r
234         }\r
235 \r
236 }\r