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