216be4f559dca41ff824b6dc19c58b0805031efe
[aaf/cadi.git] / client / src / main / java / com / att / cadi / locator / PropertyLocator.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.locator;\r
24 \r
25 import java.io.IOException;\r
26 import java.net.InetAddress;\r
27 import java.net.InetSocketAddress;\r
28 import java.net.Socket;\r
29 import java.net.URI;\r
30 import java.net.URISyntaxException;\r
31 import java.net.UnknownHostException;\r
32 import java.util.ArrayList;\r
33 import java.util.List;\r
34 import java.security.SecureRandom;\r
35 import java.util.Timer;\r
36 import java.util.TimerTask;\r
37 \r
38 import com.att.cadi.Locator;\r
39 import com.att.cadi.LocatorException;\r
40 import com.att.inno.env.util.Split;\r
41 \r
42 public class PropertyLocator implements Locator<URI> {\r
43         private final URI [] orig;\r
44         private PLItem[] current;\r
45         private int end;\r
46         private final SecureRandom random;\r
47         private URI[] resolved;\r
48         private long lastRefreshed=0L;\r
49         private long minRefresh;\r
50         private long backgroundRefresh;\r
51 \r
52         public PropertyLocator(String locList) throws LocatorException {\r
53                 this(locList,10000L, 1000*60*20); // defaults, do not refresh more than once in 10 seconds, Refresh Locator every 20 mins.\r
54         }\r
55         /**\r
56          * comma delimited root url list\r
57          * \r
58          * @param locList\r
59          * @throws LocatorException\r
60          */\r
61         public PropertyLocator(String locList, long minRefreshMillis, long backgroundRefreshMillis) throws LocatorException {\r
62                 minRefresh = minRefreshMillis;\r
63                 backgroundRefresh = backgroundRefreshMillis;\r
64                 if(locList==null) {\r
65                         throw new LocatorException("No Location List given for PropertyLocator");\r
66                 }\r
67                 String[] locarray = Split.split(',',locList);\r
68                 List<URI> uriList = new ArrayList<URI>();\r
69                 \r
70                 random = new SecureRandom();\r
71                 \r
72                 for(int i=0;i<locarray.length;++i) {\r
73                         try {\r
74                                 int range = locarray[i].indexOf(":[");\r
75                                 if(range<0) {\r
76                                         uriList.add(new URI(locarray[i]));\r
77                                 } else {\r
78                                         int dash = locarray[i].indexOf('-',range+2);\r
79                                         int brac = locarray[i].indexOf(']',dash+1);\r
80                                         int start = Integer.parseInt(locarray[i].substring(range+2, dash));\r
81                                         int end = Integer.parseInt(locarray[i].substring(dash+1, brac));\r
82                                         for(int port=start;port<=end;++port) {\r
83                                                 uriList.add(new URI(locarray[i].substring(0, range+1)+port));\r
84                                         }\r
85                                 }\r
86                         } catch (NumberFormatException nf) {\r
87                                 throw new LocatorException("Invalid URI format: " + locarray[i]);\r
88                         } catch (URISyntaxException e) {\r
89                                 throw new LocatorException(e);\r
90                         }\r
91                 }\r
92                 orig = new URI[uriList.size()];\r
93                 uriList.toArray(orig);\r
94 \r
95                 refresh();\r
96                 new Timer("PropertyLocator Refresh Timer",true).scheduleAtFixedRate(new TimerTask() {\r
97                         @Override\r
98                         public void run() {\r
99                                 refresh();\r
100                         }\r
101                 }, backgroundRefresh,backgroundRefresh);\r
102 \r
103         }\r
104 \r
105         @Override\r
106         public URI get(Item item) throws LocatorException {\r
107                 synchronized(orig) {\r
108                         if(item==null) {\r
109                                 return null;\r
110                         } else {\r
111                                 return resolved[((PLItem)item).idx];\r
112                         }\r
113                 }\r
114         }\r
115 \r
116         @Override\r
117         public Item first() throws LocatorException {\r
118                 return end>0?current[0]:null;\r
119         }\r
120 \r
121         @Override\r
122         public boolean hasItems() {\r
123                 return end>0;\r
124         }\r
125 \r
126         @Override\r
127         public Item next(Item item) throws LocatorException {\r
128                 if(item==null) {\r
129                         return null;\r
130                 } else {\r
131                         int spot;\r
132                         if((spot=(((PLItem)item).order+1))>=end)return null;\r
133                         return current[spot];\r
134                 }\r
135         }\r
136 \r
137         @Override\r
138         public synchronized void invalidate(Item item) throws LocatorException {\r
139                 if(--end<=0) {\r
140                         refresh();\r
141                         return;\r
142                 }\r
143                 PLItem pli = (PLItem)item;\r
144                 int i,order;\r
145                 for(i=0;i<end;++i) {\r
146                         if(pli==current[i])break;\r
147                 }\r
148                 order = current[i].order;\r
149                 for(;i<end;++i) {\r
150                         current[i]=current[i+1];\r
151                         current[i].order=order++;\r
152                 }\r
153                 current[end]=pli;\r
154         }\r
155 \r
156         @Override\r
157         public Item best() throws LocatorException {\r
158                 if(current.length==0) {\r
159                         refresh();\r
160                 }\r
161                 switch(current.length) {\r
162                         case 0:\r
163                                 return null;\r
164                         case 1:\r
165                                 return current[0];\r
166                         default:\r
167                                 return current[Math.abs(random.nextInt())%current.length];\r
168                 }\r
169         }\r
170 \r
171         @Override\r
172         public synchronized boolean refresh() {\r
173                 if(System.currentTimeMillis()>lastRefreshed) {\r
174                         // Build up list\r
175                         List<URI> resolve = new ArrayList<URI>();\r
176                         String realname;\r
177                         for(int i = 0; i < orig.length ; ++i) {\r
178                                 try {\r
179                                         InetAddress ia[] = InetAddress.getAllByName(orig[i].getHost());\r
180 \r
181                                         URI o,n;\r
182                                         for(int j=0;j<ia.length;++j) {\r
183                                                 o = orig[i];\r
184                                                 Socket socket = new Socket();\r
185                                                 try {\r
186                                                         realname=ia[j].getCanonicalHostName();\r
187                                                         socket.connect(new InetSocketAddress(realname,o.getPort()),3000);\r
188                                                         if(socket.isConnected()) {\r
189                                                                 n = new URI(\r
190                                                                                 o.getScheme(),\r
191                                                                                 o.getUserInfo(),\r
192                                                                                 realname,\r
193                                                                                 o.getPort(),\r
194                                                                                 o.getPath(),\r
195                                                                                 o.getQuery(),\r
196                                                                                 o.getFragment()\r
197                                                                                 );\r
198                                                                 resolve.add(n);\r
199                                                         }\r
200                                                 } catch (IOException e) {\r
201                                                 } finally {\r
202                                                         if(!socket.isClosed()) {\r
203                                                                 try {\r
204                                                                         socket.close();\r
205                                                                 } catch (IOException e) {\r
206                                                                         // nothing to do.\r
207                                                                 }\r
208                                                         }\r
209                                                 }\r
210                                         }\r
211                                 } catch (UnknownHostException | URISyntaxException e) {\r
212                                         // Note: Orig Name already known as valid, based on constructor\r
213                                 }\r
214                         }\r
215                         end=resolve.size();\r
216                         PLItem[] newCurrent;\r
217                         if(current==null || current.length!=end) {\r
218                                 newCurrent = new PLItem[end];\r
219                         } else {\r
220                                 newCurrent = current;\r
221                         }\r
222         \r
223                         for(int i=0; i< end; ++i) {\r
224                                 if(newCurrent[i]==null){\r
225                                         newCurrent[i]=new PLItem(i);\r
226                                 } else {\r
227                                         newCurrent[i].idx=newCurrent[i].order=i;\r
228                                 }\r
229                         }\r
230                         synchronized(orig) {\r
231                                 resolved = new URI[end];\r
232                                 resolve.toArray(resolved);\r
233                                 current = newCurrent;\r
234                         }\r
235                         lastRefreshed = System.currentTimeMillis()+minRefresh;\r
236                         return !resolve.isEmpty();\r
237                 } else {\r
238                         return false;\r
239                 }\r
240         }\r
241         \r
242         private class PLItem implements Item {\r
243                 public int idx,order;\r
244                 \r
245                 public PLItem(int i) {\r
246                         idx = order =i;\r
247                 }\r
248                 \r
249                 public String toString() {\r
250                         return "Item: " + idx + " order: " + order;\r
251                 }\r
252         }\r
253 \r
254         public String toString() {\r
255                 StringBuilder sb = new StringBuilder();\r
256                 boolean first = true;\r
257                 for(URI uri : orig) {\r
258                         boolean isResolved=false;\r
259                         if(uri!=null) {\r
260                                 if(first) {\r
261                                         first = false;\r
262                                 } else {\r
263                                         sb.append(", ");\r
264                                 }\r
265                                 sb.append(uri.toString());\r
266                                 sb.append(" [");\r
267                                 for(URI u2 : resolved) {\r
268                                         if(uri.equals(u2)) {\r
269                                                 isResolved = true;\r
270                                                 break;\r
271                                         }\r
272                                 }\r
273                                 sb.append(isResolved?"X]\n":" ]");\r
274                         }\r
275                 }\r
276                 return sb.toString();\r
277         }\r
278         \r
279         public void destroy() {\r
280         }\r
281 }\r