Add Notice of aaf/cadi source moving to aaf/authz
[aaf/cadi.git] / client / src / main / java / org / onap / aaf / cadi / locator / HotPeerLocator.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.locator;\r
24 \r
25 import org.onap.aaf.cadi.Access;\r
26 import org.onap.aaf.cadi.Locator;\r
27 import org.onap.aaf.cadi.LocatorException;\r
28 import org.onap.aaf.cadi.Access.Level;\r
29 import org.onap.aaf.cadi.routing.GreatCircle;\r
30 \r
31 import org.onap.aaf.inno.env.util.Split;\r
32 \r
33 /**\r
34  * This Locator is to handle Hot Peer load protection, when the Servers are \r
35  *      1) Static\r
36  *      2) Well known client URL\r
37  * \r
38  * The intention is to change traffic over to the Hot Peer, if a server goes down, and reinstate\r
39  * when it is back up.\r
40  * \r
41  * Example of this kind of Service is a MS Certificate Server\r
42  * \r
43  *\r
44  *\r
45  * @param <CLIENT>\r
46  */\r
47 public abstract class HotPeerLocator<CLIENT> implements Locator<CLIENT> {\r
48                 private final String[] urlstrs;\r
49                 private final CLIENT[] clients;\r
50                 private final long[] failures;\r
51                 private final double[] distances;\r
52                 private int preferred;\r
53                 private long invalidateTime;\r
54                 private Thread refreshThread;\r
55                 protected Access access;\r
56 \r
57                 /**\r
58                  * Construct:  Expect one or more Strings in the form:\r
59                  *              192.555.112.223:39/38.88087/-77.30122\r
60                  *    separated by commas\r
61                  * \r
62                  * @param trans\r
63                  * @param urlstr\r
64                  * @param invalidateTime\r
65                  * @param localLatitude\r
66                  * @param localLongitude\r
67                  * @throws LocatorException\r
68                  */\r
69                 @SuppressWarnings("unchecked")\r
70                 protected HotPeerLocator(Access access, final String urlstr, final long invalidateTime, final String localLatitude, final String localLongitude) throws LocatorException {\r
71                         this.access = access;\r
72                         urlstrs = Split.split(',', urlstr);\r
73                         clients = (CLIENT[])new Object[urlstrs.length];\r
74                         failures = new long[urlstrs.length];\r
75                         distances= new double[urlstrs.length];\r
76                         this.invalidateTime = invalidateTime;\r
77                         \r
78                         double distance = Double.MAX_VALUE;\r
79                         for(int i=0;i<urlstrs.length;++i) {\r
80                                 String[] info = Split.split('/', urlstrs[i]);\r
81                                 if(info.length<3) {\r
82                                         throw new LocatorException("Configuration needs LAT and LONG, i.e. ip:port/lat/long");\r
83                                 }\r
84                                 try {\r
85                                         clients[i] = _newClient(urlstrs[i]);\r
86                                         failures[i] = 0L;\r
87                                 } catch(LocatorException le) {\r
88                                         failures[i] = System.currentTimeMillis()+invalidateTime;\r
89                                 }\r
90                                 \r
91                                 double d = GreatCircle.calc(info[1],info[2],localLatitude,localLongitude);\r
92                                 distances[i]=d;\r
93                                 \r
94                                 // find preferred server\r
95                                 if(d<distance) {\r
96                                         preferred = i;\r
97                                         distance=d;\r
98                                 }\r
99                         }\r
100                         \r
101                         access.printf(Level.INIT,"Preferred Client is %s",urlstrs[preferred]);\r
102                         for(int i=0;i<urlstrs.length;++i) {\r
103                                 if(i!=preferred) {\r
104                                         access.printf(Level.INIT,"Alternate Client is %s",urlstrs[i]);\r
105                                 }\r
106                         }\r
107                 }\r
108                 \r
109                 protected abstract CLIENT _newClient(String hostInfo) throws LocatorException;\r
110                 /**\r
111                  * If client can reconnect, then return.  Otherwise, destroy and return null;\r
112                  * @param client\r
113                  * @return\r
114                  * @throws LocatorException\r
115                  */\r
116                 protected abstract CLIENT _invalidate(CLIENT client);\r
117                 \r
118                 protected abstract void _destroy(CLIENT client);\r
119                 \r
120                 @Override\r
121                 public Item best() throws LocatorException {\r
122                         if(failures[preferred]==0L) {\r
123                                 return new HPItem(preferred);\r
124                         } else {\r
125                                 long now = System.currentTimeMillis();\r
126                                 double d = Double.MAX_VALUE;\r
127                                 int best = -1;\r
128                                 boolean tickle = false;\r
129                                 // try for best existing client\r
130                                 for(int i=0;i<urlstrs.length;++i) {\r
131                                         if(failures[i]<now && distances[i]<d) {\r
132                                                 if(clients[i]!=null) {\r
133                                                         best = i;\r
134                                                         break;\r
135                                                 } else {\r
136                                                         tickle = true; // There's some failed clients which can be restored\r
137                                                 }\r
138                                         }\r
139                                 }\r
140                                 if(best<0 && tickle) {\r
141                                         tickle=false;\r
142                                         if(refresh()) {\r
143                                                 // try again\r
144                                                 for(int i=0;i<urlstrs.length;++i) {\r
145                                                         if(failures[i]==0L && distances[i]<d) {\r
146                                                                 if(clients[i]!=null) {\r
147                                                                         best = i;\r
148                                                                         break;\r
149                                                                 }\r
150                                                         }\r
151                                                 }\r
152                                         }\r
153                                 }\r
154                         \r
155                                 /*\r
156                                  * If a valid client is available, but there are some that can refresh, return the client immediately\r
157                                  * but start a Thread to do the background Client setup.\r
158                                  */\r
159                                 if(tickle) {\r
160                                         synchronized(clients) {\r
161                                                 if(refreshThread==null) {\r
162                                                         refreshThread = new Thread(new Runnable(){\r
163                                                                 @Override\r
164                                                                 public void run() {\r
165                                                                         refresh();\r
166                                                                         refreshThread = null;\r
167                                                                 }\r
168                                                         });\r
169                                                         refreshThread.setDaemon(true);\r
170                                                         refreshThread.start();\r
171                                                 }\r
172                                         }\r
173                                 }\r
174                                 \r
175                                 if(best<0) {\r
176                                         throw new LocatorException("No Clients available");\r
177                                 }\r
178 \r
179                                 \r
180                                 return new HPItem(best);\r
181                         }\r
182                 }\r
183                 \r
184 \r
185                 @Override\r
186                 public CLIENT get(Item item) throws LocatorException {\r
187                         HPItem hpi = (HPItem)item;\r
188                         CLIENT c = clients[hpi.idx];\r
189                         if(c==null) {\r
190                                 if(failures[hpi.idx]>System.currentTimeMillis()) {\r
191                                         throw new LocatorException("Client requested is invalid");      \r
192                                 } else {\r
193                                         synchronized(clients) {\r
194                                                 c = _newClient(urlstrs[hpi.idx]);\r
195                                                 failures[hpi.idx]=0L;\r
196                                         }\r
197                                 }\r
198                         } else if(failures[hpi.idx]>0){\r
199                                 throw new LocatorException("Client requested is invalid");\r
200                         }\r
201                         return c;\r
202                 }\r
203                 \r
204                 public String info(Item item) {\r
205                         HPItem hpi = (HPItem)item;\r
206                         if(hpi!=null && hpi.idx<urlstrs.length) {\r
207                                 return urlstrs[hpi.idx];\r
208                         } else {\r
209                                 return "Invalid Item";\r
210                         }\r
211                 }\r
212 \r
213                 @Override\r
214                 public boolean hasItems() {\r
215                         for(int i=0;i<clients.length;++i) {\r
216                                 if(clients[i]!=null && failures[i]==0L) {\r
217                                         return true;\r
218                                 }\r
219                         }\r
220                         return false;\r
221                 }\r
222                 \r
223                 @Override\r
224                 public synchronized void invalidate(Item item) throws LocatorException {\r
225                         HPItem hpi = (HPItem)item;\r
226                         failures[hpi.idx] = System.currentTimeMillis() + invalidateTime;\r
227                         CLIENT c = clients[hpi.idx];\r
228                         clients[hpi.idx] = _invalidate(c);\r
229                 }\r
230                 \r
231                 @Override\r
232                 public Item first() throws LocatorException {\r
233                         return new HPItem(0);\r
234                 }\r
235                 \r
236                 @Override\r
237                 public Item next(Item item) throws LocatorException {\r
238                         HPItem hpi = (HPItem)item;\r
239                         if(++hpi.idx>=clients.length) {\r
240                                 return null;\r
241                         }\r
242                         return hpi;\r
243                 }\r
244                 \r
245                 @Override\r
246                 public boolean refresh() {\r
247                         boolean force = !hasItems(); // If no Items at all, reset\r
248                         boolean rv = true;\r
249                         long now = System.currentTimeMillis();\r
250                         for(int i=0;i<clients.length;++i) {\r
251                                 if(failures[i]>0L && (failures[i]<now || force)) { // retry\r
252                                         try {\r
253                                                 synchronized(clients) {\r
254                                                         if(clients[i]==null) {\r
255                                                                 clients[i]=_newClient(urlstrs[i]);\r
256                                                         }\r
257                                                         failures[i]=0L;\r
258                                                 }\r
259                                         } catch (LocatorException e) {\r
260                                                 failures[i]=now+invalidateTime;\r
261                                                 rv = false;\r
262                                         }\r
263                                 }\r
264                         }\r
265                         return rv;\r
266                 }\r
267                 \r
268                 @Override\r
269                 public void destroy() {\r
270                         for(int i=0;i<clients.length;++i) {\r
271                                 if(clients[i]!=null) {\r
272                                         _destroy(clients[i]);\r
273                                         clients[i] = null;\r
274                                 }\r
275                         }\r
276                 }\r
277 \r
278                 private static class HPItem implements Item {\r
279                         private int idx;\r
280 \r
281                         public HPItem(int i) {\r
282                                 idx = i;\r
283                         }\r
284                 }\r
285                 \r
286 \r
287                 /*\r
288                  * Convenience Functions\r
289                  */\r
290                 public CLIENT bestClient() throws LocatorException {\r
291                         return get(best());\r
292                 }\r
293 \r
294                 public boolean invalidate(CLIENT client) throws LocatorException {\r
295                         for(int i=0;i<clients.length;++i) {\r
296                                 if(clients[i]==client) { // yes, "==" is appropriate here.. Comparing Java Object Reference\r
297                                         invalidate(new HPItem(i));\r
298                                         return true;\r
299                                 }\r
300                         }\r
301                         return false;\r
302                 }\r
303 \r
304         }\r