View Javadoc
1   /*
2     (C) Copyright IBM Corp. 2007, 2010
3    
4     THIS FILE IS PROVIDED UNDER THE TERMS OF THE ECLIPSE PUBLIC LICENSE 
5     ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE 
6     CONSTITUTES RECIPIENTS ACCEPTANCE OF THE AGREEMENT.
7    
8     You can obtain a current copy of the Eclipse Public License from
9     http://www.opensource.org/licenses/eclipse-1.0.php
10   
11    @author : Endre Bak, IBM, ebak@de.ibm.com
12   * 
13   * Change History
14   * Flag       Date        Prog         Description
15   *------------------------------------------------------------------------------- 
16   * 1804402    2007-09-28  ebak         IPv6 ready SLP
17   * 2003590    2008-06-30  blaschke-oss Change licensing from CPL to EPL
18   * 2524131    2009-01-21  raman_arora  Upgrade client to JDK 1.5 (Phase 1)
19   * 2531371    2009-02-10  raman_arora  Upgrade client to JDK 1.5 (Phase 2)
20   * 3023349    2010-07-02  blaschke-oss SLP uses # constructor instead of valueOf
21   */
22  
23  package org.metricshub.wbem.sblim.slp.internal.sa;
24  
25  /*-
26   * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
27   * WBEM Java Client
28   * ჻჻჻჻჻჻
29   * Copyright 2023 - 2025 MetricsHub
30   * ჻჻჻჻჻჻
31   * Licensed under the Apache License, Version 2.0 (the "License");
32   * you may not use this file except in compliance with the License.
33   * You may obtain a copy of the License at
34   *
35   *      http://www.apache.org/licenses/LICENSE-2.0
36   *
37   * Unless required by applicable law or agreed to in writing, software
38   * distributed under the License is distributed on an "AS IS" BASIS,
39   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
40   * See the License for the specific language governing permissions and
41   * limitations under the License.
42   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
43   */
44  
45  import java.io.IOException;
46  import java.net.UnknownHostException;
47  import java.util.ArrayList;
48  import java.util.HashMap;
49  import java.util.HashSet;
50  import java.util.Iterator;
51  import java.util.List;
52  import org.metricshub.wbem.sblim.slp.ServiceLocationAttribute;
53  import org.metricshub.wbem.sblim.slp.ServiceType;
54  import org.metricshub.wbem.sblim.slp.ServiceURL;
55  import org.metricshub.wbem.sblim.slp.internal.IPv6MulticastAddressFactory;
56  import org.metricshub.wbem.sblim.slp.internal.Net;
57  import org.metricshub.wbem.sblim.slp.internal.SLPConfig;
58  import org.metricshub.wbem.sblim.slp.internal.SLPDefaults;
59  import org.metricshub.wbem.sblim.slp.internal.TRC;
60  
61  /**
62   * ServiceTable
63   *
64   */
65  public class ServiceTable {
66  	DatagramThread iDgramThread;
67  
68  	private boolean iUseV6 = Net.hasIPv6() && SLPConfig.getGlobalCfg().useIPv6();
69  
70  	class AddressHashTable {
71  
72  		class Counter {
73  			/**
74  			 * iValue
75  			 */
76  			public int iValue = 1;
77  		}
78  
79  		/**
80  		 * AddressHash -> Counter
81  		 */
82  		private HashMap<Integer, Counter> iMap = new HashMap<Integer, Counter>();
83  
84  		/**
85  		 * register
86  		 *
87  		 * @param pType
88  		 * @throws UnknownHostException
89  		 * @throws IOException
90  		 */
91  		public void register(ServiceType pType) throws UnknownHostException, IOException {
92  			Integer hash = Integer.valueOf(IPv6MulticastAddressFactory.getSrvTypeHash(pType));
93  			TRC.debug("srvType:" + pType + ", hash:" + hash);
94  			Counter cntr = this.iMap.get(hash);
95  			if (cntr == null) {
96  				cntr = new Counter();
97  				this.iMap.put(hash, cntr);
98  				ServiceTable.this.iDgramThread.joinGroup(
99  						IPv6MulticastAddressFactory.get(SLPDefaults.IPV6_MULTICAST_SCOPE, hash.intValue())
100 					);
101 			} else {
102 				++cntr.iValue;
103 			}
104 		}
105 
106 		/**
107 		 * unregister
108 		 *
109 		 * @param pType
110 		 * @throws UnknownHostException
111 		 * @throws IOException
112 		 */
113 		public void unregister(ServiceType pType) throws UnknownHostException, IOException {
114 			Integer hash = Integer.valueOf(IPv6MulticastAddressFactory.getSrvTypeHash(pType));
115 			Counter cntr = this.iMap.get(hash);
116 			if (cntr == null) return;
117 			if (cntr.iValue <= 1) {
118 				this.iMap.remove(hash);
119 				ServiceTable.this.iDgramThread.leaveGroup(
120 						IPv6MulticastAddressFactory.get(SLPDefaults.IPV6_MULTICAST_SCOPE, hash.intValue())
121 					);
122 			} else {
123 				--cntr.iValue;
124 			}
125 		}
126 	}
127 
128 	private static class ServiceEntry {
129 		private ServiceURL iSrvURL;
130 
131 		private List<ServiceLocationAttribute> iAttribs;
132 
133 		private List<String> iScopes;
134 
135 		/**
136 		 * Ctor.
137 		 *
138 		 * @param pSrvURL
139 		 * @param pAttribs
140 		 * @param pScopes
141 		 */
142 		public ServiceEntry(ServiceURL pSrvURL, List<ServiceLocationAttribute> pAttribs, List<String> pScopes) {
143 			set(pSrvURL, pAttribs, pScopes);
144 		}
145 
146 		/**
147 		 * set
148 		 *
149 		 * @param pSrvURL
150 		 * @param pAttribs
151 		 * @param pScopes
152 		 */
153 		public void set(ServiceURL pSrvURL, List<ServiceLocationAttribute> pAttribs, List<String> pScopes) {
154 			this.iSrvURL = pSrvURL;
155 			this.iAttribs = pAttribs;
156 			this.iScopes = pScopes;
157 		}
158 
159 		/**
160 		 * getServiceURL
161 		 *
162 		 * @return ServiceURL
163 		 */
164 		public ServiceURL getServiceURL() {
165 			return this.iSrvURL;
166 		}
167 
168 		/**
169 		 * getServiceType
170 		 *
171 		 * @return ServiceType
172 		 */
173 		public ServiceType getServiceType() {
174 			return this.iSrvURL.getServiceType();
175 		}
176 
177 		/**
178 		 * getAttributes
179 		 *
180 		 * @return List
181 		 */
182 		public List<ServiceLocationAttribute> getAttributes() {
183 			return this.iAttribs;
184 		}
185 
186 		/**
187 		 * getScopes
188 		 *
189 		 * @return List
190 		 */
191 		public List<String> getScopes() {
192 			return this.iScopes;
193 		}
194 
195 		/**
196 		 * hasMatchingScope
197 		 *
198 		 * @param pScopes
199 		 * @return boolean
200 		 */
201 		public boolean hasMatchingScope(List<String> pScopes) {
202 			if (pScopes == null) return false;
203 			Iterator<String> itr = pScopes.iterator();
204 			while (itr.hasNext()) if (hasScope(itr.next())) return true;
205 			return false;
206 		}
207 
208 		@Override
209 		public String toString() {
210 			return "url:" + this.iSrvURL + ", attribs:" + dumpList(this.iAttribs) + ", scopes:" + dumpList(this.iScopes);
211 		}
212 
213 		private boolean hasScope(String pScope) {
214 			return this.iScopes == null ? false : this.iScopes.contains(pScope);
215 		}
216 	}
217 
218 	static class ServiceEntryList extends ArrayList<Object> {
219 		private static final long serialVersionUID = 1L;
220 
221 		/**
222 		 * get
223 		 *
224 		 * @param pSrvURL
225 		 * @return ServiceEntry
226 		 */
227 		public ServiceEntry get(ServiceURL pSrvURL) {
228 			for (int i = 0; i < size(); i++) {
229 				ServiceEntry entry = (ServiceEntry) get(i);
230 				if (pSrvURL.equals(entry.getServiceURL())) return entry;
231 			}
232 			return null;
233 		}
234 
235 		/**
236 		 * remove
237 		 *
238 		 * @param pSrvURL
239 		 */
240 		public void remove(ServiceURL pSrvURL) {
241 			for (int i = 0; i < size(); i++) {
242 				ServiceEntry entry = (ServiceEntry) get(i);
243 				if (pSrvURL.equals(entry.getServiceURL())) {
244 					remove(i);
245 					break;
246 				}
247 			}
248 		}
249 
250 		/**
251 		 * getServiceURLs
252 		 *
253 		 * @param pSrvType
254 		 * @param pScopes
255 		 * @return List
256 		 */
257 		public List<ServiceURL> getServiceURLs(ServiceType pSrvType, List<String> pScopes) {
258 			if (pSrvType == null) return null;
259 			List<ServiceURL> srvURLs = null;
260 			for (int i = 0; i < size(); i++) {
261 				ServiceEntry entry = (ServiceEntry) get(i);
262 				if (!entry.hasMatchingScope(pScopes)) continue;
263 				if (pSrvType.getPrincipleTypeName().equals(entry.getServiceType().getPrincipleTypeName())) {
264 					if (srvURLs == null) srvURLs = new ArrayList<ServiceURL>();
265 					srvURLs.add(entry.getServiceURL());
266 				}
267 			}
268 			return srvURLs;
269 		}
270 	}
271 
272 	private ServiceEntryList iSrvEntryTable = new ServiceEntryList();
273 
274 	private AddressHashTable iAddressHashTable = new AddressHashTable();
275 
276 	/**
277 	 * Ctor.
278 	 *
279 	 * @param pDgramThread
280 	 */
281 	public ServiceTable(DatagramThread pDgramThread) {
282 		this.iDgramThread = pDgramThread;
283 	}
284 
285 	/**
286 	 * add
287 	 *
288 	 * @param pSrvURL
289 	 * @param pAttrList
290 	 * @param pScopes
291 	 * @throws UnknownHostException
292 	 * @throws IOException
293 	 */
294 	public synchronized void add(ServiceURL pSrvURL, List<ServiceLocationAttribute> pAttrList, List<String> pScopes)
295 		throws UnknownHostException, IOException {
296 		if (pSrvURL == null) return;
297 		TRC.debug("add URL:" + pSrvURL + ", scopes:" + dumpList(pScopes));
298 		ServiceEntry srvEntry = this.iSrvEntryTable.get(pSrvURL);
299 		if (srvEntry == null) {
300 			this.iSrvEntryTable.add(new ServiceEntry(pSrvURL, pAttrList, pScopes));
301 		} else {
302 			srvEntry.set(pSrvURL, pAttrList, pScopes);
303 		}
304 
305 		if (!this.iUseV6) return;
306 		this.iAddressHashTable.register(pSrvURL.getServiceType());
307 	}
308 
309 	/**
310 	 * remove
311 	 *
312 	 * @param pSrvURL
313 	 * @throws UnknownHostException
314 	 * @throws IOException
315 	 */
316 	public synchronized void remove(ServiceURL pSrvURL) throws UnknownHostException, IOException {
317 		this.iSrvEntryTable.remove(pSrvURL);
318 
319 		if (!this.iUseV6) return;
320 		this.iAddressHashTable.unregister(pSrvURL.getServiceType());
321 	}
322 
323 	/**
324 	 * getServiceURLs
325 	 *
326 	 * @param pSrvType
327 	 * @param pScopes
328 	 * @return List ServiceURL
329 	 */
330 	public synchronized List<ServiceURL> getServiceURLs(ServiceType pSrvType, List<String> pScopes) {
331 		TRC.debug("getServiceURLs srvType:" + pSrvType + ", scopes:" + dumpList(pScopes));
332 		List<ServiceURL> list = this.iSrvEntryTable.getServiceURLs(pSrvType, pScopes);
333 		return list;
334 	}
335 
336 	/**
337 	 * getAttributes
338 	 *
339 	 * @param pSrvURL
340 	 * @param pScopes
341 	 * @return List ServiceLocationAttribute
342 	 */
343 	public synchronized List<ServiceLocationAttribute> getAttributes(ServiceURL pSrvURL, List<String> pScopes) {
344 		if (pSrvURL == null) return null;
345 		if (pSrvURL.getURLPath() == null) return getAttributes(pSrvURL.getServiceType(), pScopes);
346 		ServiceEntry entry = this.iSrvEntryTable.get(pSrvURL);
347 		return entry == null ? null : entry.getAttributes();
348 	}
349 
350 	/**
351 	 * getAttributes
352 	 *
353 	 * @param pSrvType
354 	 * @param pScopes
355 	 * @return List ServiceLocationAttribute
356 	 */
357 	public synchronized List<ServiceLocationAttribute> getAttributes(ServiceType pSrvType, List<String> pScopes) {
358 		if (pSrvType == null) return null;
359 		HashSet<ServiceLocationAttribute> attribs = new HashSet<ServiceLocationAttribute>();
360 		for (int i = 0; i < this.iSrvEntryTable.size(); i++) {
361 			ServiceEntry entry = (ServiceEntry) this.iSrvEntryTable.get(i);
362 			ServiceType srvType = entry.getServiceType();
363 			if (pSrvType.equals(srvType)) attribs.addAll(entry.getAttributes());
364 		}
365 		return new ArrayList<ServiceLocationAttribute>(attribs);
366 	}
367 
368 	/**
369 	 * getServiceTypes
370 	 *
371 	 * @param pScopes
372 	 * @return List ServiceType
373 	 */
374 	public synchronized List<ServiceType> getServiceTypes(List<String> pScopes) {
375 		List<ServiceType> srvTypes = null;
376 		for (int i = 0; i < this.iSrvEntryTable.size(); i++) {
377 			ServiceEntry entry = (ServiceEntry) this.iSrvEntryTable.get(i);
378 			if (entry.hasMatchingScope(pScopes)) {
379 				ServiceType srvType = entry.getServiceType();
380 				if (srvType == null) continue;
381 				if (srvTypes == null) srvTypes = new ArrayList<ServiceType>();
382 				srvTypes.add(srvType);
383 			}
384 		}
385 		return srvTypes;
386 	}
387 
388 	static String dumpList(List<?> pList) {
389 		return dumpList(pList, ",");
390 	}
391 
392 	private static String dumpList(List<?> pList, String pSep) {
393 		if (pList == null) return "null";
394 		StringBuffer buf = new StringBuffer();
395 		Iterator<?> itr = pList.iterator();
396 		boolean first = true;
397 		while (itr.hasNext()) {
398 			if (!first) buf.append(pSep);
399 			buf.append(itr.next().toString());
400 			first = false;
401 		}
402 		return buf.toString();
403 	}
404 }