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