[AAF-21] Initial code import
[aaf/cadi.git] / client / src / main / java / com / att / cadi / dme2 / DME2Locator.java
1 /*******************************************************************************\r
2  * ============LICENSE_START====================================================\r
3  * * org.onap.aai\r
4  * * ===========================================================================\r
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
6  * * Copyright © 2017 Amdocs\r
7  * * ===========================================================================\r
8  * * Licensed under the Apache License, Version 2.0 (the "License");\r
9  * * you may not use this file except in compliance with the License.\r
10  * * You may obtain a copy of the License at\r
11  * * \r
12  *  *      http://www.apache.org/licenses/LICENSE-2.0\r
13  * * \r
14  *  * Unless required by applicable law or agreed to in writing, software\r
15  * * distributed under the License is distributed on an "AS IS" BASIS,\r
16  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
17  * * See the License for the specific language governing permissions and\r
18  * * limitations under the License.\r
19  * * ============LICENSE_END====================================================\r
20  * *\r
21  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
22  * *\r
23  ******************************************************************************/\r
24 package com.att.cadi.dme2;\r
25 \r
26 \r
27 import java.net.InetAddress;\r
28 import java.net.URI;\r
29 import java.net.URISyntaxException;\r
30 import java.net.UnknownHostException;\r
31 import java.util.Arrays;\r
32 import java.util.Comparator;\r
33 import java.util.Random;\r
34 \r
35 //\r
36 import com.att.aft.dme2.api.DME2Exception;\r
37 import com.att.aft.dme2.api.DME2Manager;\r
38 import com.att.aft.dme2.api.DME2Server;\r
39 import com.att.aft.dme2.manager.registry.DME2Endpoint;\r
40 import com.att.cadi.Access;\r
41 import com.att.cadi.Access.Level;\r
42 import com.att.cadi.Locator;\r
43 import com.att.cadi.LocatorException;\r
44 \r
45 public class DME2Locator implements Locator {\r
46         private DME2Manager dm;\r
47         private DME2Endpoint[] endpoints;\r
48         private Access access;\r
49         private String service;\r
50         private String version;\r
51         private String routeOffer;\r
52         private String envContext;\r
53         private String thisMachine;\r
54         private String pathInfo;\r
55         private int thisPort;\r
56         private boolean removeSelf;\r
57         private final static Random random = new Random();\r
58 \r
59         // Default is to not bother trying to remove self\r
60         public DME2Locator(Access access, DME2Manager dm, String service, String version, String envContext, String routeOffer) throws DME2Exception, UnknownHostException, LocatorException {\r
61                 this(access,dm,service,version,envContext,routeOffer,false);\r
62         }\r
63         \r
64         public DME2Locator(Access access, DME2Manager dm, String service, String version, String envContext, String routeOffer, boolean removeSelf) throws DME2Exception, UnknownHostException, LocatorException {\r
65                 this.access = access;\r
66                 if(dm==null) {\r
67                         this.dm = new DME2Manager("DME2Locator created DME2Manager",System.getProperties());\r
68                 } else {\r
69                         this.dm = dm;\r
70                 }\r
71                 this.service = service;\r
72                 this.version = version;\r
73                 this.envContext = envContext;\r
74                 this.routeOffer = routeOffer;\r
75                 refresh();\r
76                 DME2Server server = dm.getServer(); \r
77                 if(server == null) {\r
78                         thisMachine = InetAddress.getLocalHost().getHostName();\r
79                         thisPort = 0;\r
80                 } else {\r
81                         try {\r
82                                 thisMachine = server.getServerProperties().getHostname();\r
83                                 //thisPort = server.getPort();\r
84                                 thisPort = server.getServerProperties().getPort();\r
85                         } catch(NullPointerException np) { // BAD BOY, DME2...\r
86                                 access.log(Level.ERROR, "WARNING: DME2 threw a NullPointer Exception getting Server Machine and Port");\r
87                                 thisMachine = InetAddress.getLocalHost().getHostName();\r
88                                 thisPort = 0;\r
89                         }\r
90                 }\r
91                 this.removeSelf = removeSelf;\r
92         }\r
93 \r
94         // Default is to not bother trying to remove self\r
95         public DME2Locator(Access access, DME2Manager dm, String aafurl) throws DME2Exception, UnknownHostException, LocatorException {\r
96                 this(access,dm,aafurl,false);\r
97         }\r
98         \r
99         public DME2Locator(Access access, DME2Manager dm, String aafurl, boolean removeSelf) throws DME2Exception, UnknownHostException, LocatorException {\r
100                 if(aafurl==null) throw new LocatorException("URL is null");\r
101                 this.access = access;\r
102                 if(dm==null) {\r
103                         dm = this.dm = new DME2Manager("DME2Locator created DME2Manager",System.getProperties());\r
104                 } else {\r
105                         this.dm = dm;\r
106                 }\r
107                 String[] split = aafurl.split("/");\r
108                 StringBuilder sb = new StringBuilder();\r
109                 boolean dme2Entered = false;\r
110                 for(String s : split) {\r
111                         if(s.startsWith(     "service=")) this.service = s.substring(8);\r
112                         else if(s.startsWith("version=")) this.version = s.substring(8);\r
113                         else if(s.startsWith("envContext=")) this.envContext = s.substring(11);\r
114                         else if(s.startsWith("routeOffer=")) {\r
115                                 this.routeOffer = s.substring(11);\r
116                                 dme2Entered = true;\r
117                         }\r
118                         else if(dme2Entered) {\r
119                                 sb.append('/');\r
120                                 sb.append(s);\r
121                         }\r
122                         pathInfo = sb.toString();\r
123                 }\r
124                 DME2Server server = dm.getServer(); \r
125                 if(server == null) {\r
126                         thisMachine = InetAddress.getLocalHost().getHostName();\r
127                         thisPort = 0;\r
128                 } else {\r
129                         thisMachine = server.getServerProperties().getHostname();\r
130                         if(thisMachine==null) { // even if server !=null, apparently, it can be uninitialized\r
131                                 thisMachine = InetAddress.getLocalHost().getHostName();\r
132                                 thisPort = 0;\r
133                         } else {\r
134                                 try {\r
135                                         thisPort = server.getServerProperties().getPort();\r
136                                 } catch (Exception e) {\r
137                                         thisPort = 0;\r
138                                 }\r
139                         }                       \r
140                 }\r
141                 this.removeSelf=removeSelf;\r
142                 refresh();\r
143         }\r
144         \r
145         @Override\r
146         public boolean refresh() {\r
147                 try {\r
148                         dm.refresh();\r
149                         endpoints = dm.findEndpoints(service, version, envContext, routeOffer, true);\r
150                         if(removeSelf) {\r
151                                 for(int i=0;i<endpoints.length;++i) {\r
152                                         if(endpoints[i].getPort()==thisPort && endpoints[i].getHost().equals(thisMachine))\r
153                                                 endpoints[i]=null;\r
154                                 }\r
155                         }\r
156                         return endpoints.length!=0;\r
157                 } catch (Exception e) {\r
158                         access.log(Level.ERROR, e.getMessage());\r
159                 }\r
160                 return false;\r
161         }\r
162 \r
163         private String noEndpointsString() {\r
164                 StringBuilder sb = new StringBuilder("No DME2 Endpoints found for ");\r
165                 sb.append(service);\r
166                 sb.append('/');\r
167                 sb.append(version);\r
168                 sb.append('/');\r
169                 sb.append(envContext);\r
170                 sb.append('/');\r
171                 sb.append(routeOffer);\r
172                 return sb.toString();\r
173         }\r
174 \r
175         @Override\r
176         public URI get(Locator.Item item) throws LocatorException {\r
177                 if(!hasItems()) \r
178                         throw new LocatorException(noEndpointsString());\r
179                 if(item == null) \r
180                         return null;\r
181 \r
182                 Item li = ((Item)item);\r
183                 // if URI has been created, use it\r
184                 if(li.uri!=null)return li.uri;\r
185         \r
186                 // URI not created, create it\r
187                 if(li.idx<endpoints.length) {\r
188                         DME2Endpoint de = endpoints[li.idx];\r
189                         if(de!=null) {\r
190                                 try {\r
191                                         return li.uri=new URI(de.getProtocol(),null,de.getHost(),de.getPort(),pathInfo,null,null);\r
192                                 } catch (URISyntaxException e) {\r
193                                         throw new LocatorException(e);\r
194                                 }\r
195                         }\r
196                 }\r
197                 return null;\r
198         }\r
199         \r
200         @Override\r
201         public boolean hasItems() {\r
202                 return endpoints!=null && endpoints.length>0;\r
203         }\r
204 \r
205         @Override\r
206         public void invalidate(Locator.Item item) throws LocatorException {\r
207                 if(item instanceof Item) {\r
208                         int idx = ((Item)item).idx;\r
209                         if(idx<endpoints.length) {\r
210                                 DME2Endpoint uhoh = endpoints[idx]; // Sometimes, DME2Endpoint, at least on File system, returns bogus entries.\r
211                                 endpoints[idx]=null;\r
212                                 boolean noneLeft=true;\r
213                                 for(int i=0;i<endpoints.length && noneLeft;++i) {\r
214                                         noneLeft = endpoints[i]==null;\r
215                                 }\r
216                                 if(noneLeft && refresh()) { // make sure DME2 isn't giving us the same invalidated entry...\r
217                                         for(int i=0;i<endpoints.length && noneLeft;++i) {\r
218                                                 DME2Endpoint ep = endpoints[i];\r
219                                                 if(ep != null && \r
220                                                    ep.getHost().equals(uhoh.getHost()) &&\r
221                                                    ep.getPort()==uhoh.getPort()) {\r
222                                                          endpoints[i]=null;\r
223                                                 }\r
224                                         }\r
225                                 }\r
226                                 \r
227                         }\r
228                 }\r
229         }\r
230 \r
231         public class Item implements Locator.Item {\r
232                 private final int idx;\r
233                 private URI uri;\r
234                 private Item(int i) {\r
235                         idx = i;\r
236                         uri = null;\r
237                 }\r
238         }\r
239 \r
240         @Override\r
241         public Item best() throws LocatorException {\r
242                 if(!hasItems()) // checks endpoints\r
243                         if(!refresh()) throw new LocatorException("No DME2 Endpoints Available");\r
244                 \r
245                 // Some endpoints in Array are null.  Need sub array of usable endpoints\r
246                 int usable[] = new int[endpoints.length];\r
247                 int count=0;\r
248                 for(int i=0;i<endpoints.length;++i) {\r
249                         if(endpoints[i]!=null) {\r
250                                 usable[count++] = i;\r
251                         }\r
252                 }\r
253                 switch(count) {\r
254                         case 0: refresh(); return null;\r
255                         case 1: return new Item(usable[0]);\r
256                         default:\r
257                                 int samemach[] = new int[count];\r
258                                 int samecount = 0,closecount=0;\r
259                                 // has to be sortable\r
260                                 Integer closemach[] = new Integer[count];\r
261                                 \r
262                                 // Analyze for Same Machine or Remote machines\r
263                                 for(int i=0;i<count;++i) {\r
264                                         DME2Endpoint ep = endpoints[usable[i]];\r
265                                         String host = ep.getHost();\r
266                                         if(thisMachine.equalsIgnoreCase(host)) {\r
267                                                 samemach[samecount++] = usable[i];\r
268                                         } else {\r
269                                                 closemach[closecount++] = usable[i];\r
270                                         }\r
271                                 }\r
272                                 \r
273                                 switch(samecount) {\r
274                                         case 0: break;\r
275                                         case 1: return new Item(samemach[0]);\r
276                                         default: // return randomized is multiple Endpoints on local machine.\r
277                                                 int i = random.nextInt();\r
278                                                 return new Item(usable[Math.abs(i%samecount)]);\r
279                                 }\r
280                                 \r
281                                 // Analyze for closest remote\r
282                                 switch(closecount) {\r
283                                         case 0: return null;\r
284                                         case 1: return new Item(closemach[0]);\r
285                                         default: // return closest machine\r
286                                                 DoubIndex remote[] = new DoubIndex[closecount];\r
287                                                 int remotecount = 0;\r
288                                                 for(int i=0;i<closecount;++i) {\r
289                                                         DME2Endpoint de = endpoints[usable[i]];\r
290                                                         remote[remotecount++] = new DoubIndex(de.getDistance(),i);\r
291                                                 }\r
292                                                 Arrays.sort(remote,new Comparator<DoubIndex> () {\r
293                                                         @Override\r
294                                                         public int compare(DoubIndex a, DoubIndex b) {\r
295                                                                 if(a.d<b.d) return -1;\r
296                                                                 if(a.d>b.d) return 1;\r
297                                                                 return (random.nextInt()%1)==0?1:0;// randomize if the same\r
298                                                         }\r
299                                                         \r
300                                                 });\r
301                                                 return new Item(remote[0].idx);\r
302                                 }\r
303                 }\r
304         }\r
305         \r
306         private class DoubIndex {\r
307                 public final double d;\r
308                 public final int idx;\r
309                 \r
310                 public DoubIndex(double doub, int i) {\r
311                         d = doub;\r
312                         idx = i;\r
313                 }\r
314         }\r
315         @Override\r
316         public Item first() {\r
317                 if(endpoints==null)return null;\r
318                 for(int i=0;i<endpoints.length;++i) {\r
319                         if(endpoints[i]!=null)\r
320                                 return new Item(i); \r
321                 }\r
322                 return null;\r
323         }\r
324 \r
325         @Override\r
326         public Item next(Locator.Item item) throws LocatorException {\r
327                 if(endpoints==null || endpoints.length==0 || !(item instanceof Item))return null;\r
328                 int idx = ((Item)item).idx +1;\r
329                 for(int i=idx;i<endpoints.length;++i) {\r
330                         if(endpoints[i]!=null)\r
331                                 return new Item(i); \r
332                 }\r
333 // This is a mistake..  will start infinite loops\r
334 //              // Did not have any at end... try beginning\r
335 //              for(int i=0;i<idx-1;++i) {\r
336 //                      if(endpoints[i]!=null)\r
337 //                              return new Item(i); \r
338 //              }\r
339 //              // If still nothing, refresh\r
340 //              refresh();\r
341                 return null;\r
342         }\r
343 \r
344         @Override\r
345         public void destroy() {\r
346                 // TODO Auto-generated method stub\r
347                 \r
348         }\r
349 }\r