View Javadoc
1   /*
2     (C) Copyright IBM Corp. 2007, 2009
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   * 1804402    2007-11-10  ebak         IPv6 ready SLP - revision 4
18   * 1892103    2008-02-12  ebak         SLP improvements
19   * 1949918    2008-04-08  raman_arora  Malformed service URL crashes SLP discovery
20   * 2003590    2008-06-30  blaschke-oss Change licensing from CPL to EPL
21   * 2524131    2009-01-21  raman_arora  Upgrade client to JDK 1.5 (Phase 1)
22   * 2531371    2009-02-10  raman_arora  Upgrade client to JDK 1.5 (Phase 2)
23   * 2763216    2009-04-14  blaschke-oss Code cleanup: visible spelling/grammar errors
24   */
25  
26  package org.metricshub.wbem.sblim.slp.internal.ua;
27  
28  /*-
29   * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
30   * WBEM Java Client
31   * ჻჻჻჻჻჻
32   * Copyright 2023 - 2025 MetricsHub
33   * ჻჻჻჻჻჻
34   * Licensed under the Apache License, Version 2.0 (the "License");
35   * you may not use this file except in compliance with the License.
36   * You may obtain a copy of the License at
37   *
38   *      http://www.apache.org/licenses/LICENSE-2.0
39   *
40   * Unless required by applicable law or agreed to in writing, software
41   * distributed under the License is distributed on an "AS IS" BASIS,
42   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
43   * See the License for the specific language governing permissions and
44   * limitations under the License.
45   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
46   */
47  
48  import java.io.IOException;
49  import java.net.InetAddress;
50  import java.net.UnknownHostException;
51  import java.util.ArrayList;
52  import java.util.Iterator;
53  import java.util.List;
54  import java.util.NoSuchElementException;
55  import org.metricshub.wbem.sblim.slp.ServiceLocationEnumeration;
56  import org.metricshub.wbem.sblim.slp.ServiceLocationException;
57  import org.metricshub.wbem.sblim.slp.ServiceURL;
58  import org.metricshub.wbem.sblim.slp.internal.SLPDefaults;
59  import org.metricshub.wbem.sblim.slp.internal.TRC;
60  import org.metricshub.wbem.sblim.slp.internal.msg.DADescriptor;
61  import org.metricshub.wbem.sblim.slp.internal.msg.RequestMessage;
62  import org.metricshub.wbem.sblim.slp.internal.msg.ServiceRequest;
63  
64  /**
65   * SLEnumerationImpl
66   *
67   */
68  public class SLEnumerationImpl implements ServiceLocationEnumeration {
69  	private RequestMessage iReqMsg;
70  
71  	private ResultTable iResultTable;
72  
73  	private List<InetAddress> iDAList;
74  
75  	private boolean iInited = false;
76  
77  	private boolean iIsDASrvRequest;
78  
79  	private DatagramRequester iMCastRequester;
80  
81  	/**
82  	 * Ctor.
83  	 *
84  	 * @param pReqMsg
85  	 * @param pDAList
86  	 */
87  	public SLEnumerationImpl(RequestMessage pReqMsg, List<InetAddress> pDAList) {
88  		this.iReqMsg = pReqMsg;
89  		this.iResultTable = new ResultTable();
90  		this.iDAList = pDAList;
91  		this.iIsDASrvRequest = isDASrvRequest();
92  	}
93  
94  	/**
95  	 * This implementation can throw RuntimeExceptions. They can be ignored or
96  	 * used for analysis.
97  	 *
98  	 * @see ServiceLocationEnumeration#next()
99  	 */
100 	public Object next() throws NoSuchElementException {
101 		Object obj = this.iResultTable.next();
102 		if (obj instanceof Exception) throw new RuntimeException((Exception) obj);
103 		if (this.iIsDASrvRequest) {
104 			// DADescriptor is internal -> converting to ServiceURL
105 			DADescriptor daDesc = (DADescriptor) obj;
106 			return new ServiceURL(daDesc.getURL(), ServiceURL.LIFETIME_MAXIMUM);
107 		}
108 		return obj;
109 	}
110 
111 	/**
112 	 * @return next Object in Exception table
113 	 * @throws NoSuchElementException
114 	 *
115 	 *             This in internal implementation to get list of all exceptions
116 	 *             thrown/caught by parser This can throw RuntimeExceptions.
117 	 *             They can be ignored or used for analysis.
118 	 *
119 	 *             use hasNextException to check whether there exists another
120 	 *             element in Exception table
121 	 */
122 	public Object nextException() throws NoSuchElementException {
123 		return this.iResultTable.nextException();
124 	}
125 
126 	/**
127 	 * @return true if there exists another element in Exception table
128 	 *
129 	 */
130 	public boolean hasMoreExceptions() {
131 		return this.iResultTable.hasMoreExceptions();
132 	}
133 
134 	/*
135 	 * states: - init - initiated - finished
136 	 */
137 	public boolean hasMoreElements() {
138 		if (!this.iInited) {
139 			List<InetAddress> daList = null;
140 			/*
141 			 * OpenSLP DA doesn't reply to unicasted DA discovery, therefore if
142 			 * the discoverable service type is service:directory-agent a
143 			 * multicasting is done.
144 			 */
145 			if (!this.iIsDASrvRequest) {
146 				try {
147 					daList = getDAList(this.iReqMsg.getScopeList());
148 				} catch (Exception e) {
149 					throw new RuntimeException(new ServiceLocationException(ServiceLocationException.INTERNAL_ERROR, e));
150 				}
151 			}
152 			try {
153 				if (daList == null || daList.size() == 0) {
154 					setupMulticasting();
155 				} else {
156 					setupUnicasting(daList);
157 				}
158 			} catch (Exception e) {
159 				throw new RuntimeException(e);
160 			}
161 			this.iInited = true;
162 		}
163 		return this.iResultTable.hasNext();
164 	}
165 
166 	public Object nextElement() throws NoSuchElementException {
167 		return next();
168 	}
169 
170 	/**
171 	 * For diagnostic only!
172 	 *
173 	 * @return int
174 	 */
175 	public int getPort() {
176 		return this.iMCastRequester == null ? -1 : this.iMCastRequester.getPort();
177 	}
178 
179 	private boolean isDASrvRequest() {
180 		if (!(this.iReqMsg instanceof ServiceRequest)) return false;
181 		ServiceRequest srvReq = (ServiceRequest) this.iReqMsg;
182 		return SLPDefaults.DA_SERVICE_TYPE.equals(srvReq.getServiceType());
183 	}
184 
185 	/**
186 	 * @param pScopes
187 	 * @return List of DA address InetAddresses
188 	 * @throws UnknownHostException
189 	 */
190 	private List<InetAddress> getDAList(List<String> pScopes) throws UnknownHostException, IOException {
191 		if (this.iDAList != null && this.iDAList.size() > 0) return this.iDAList;
192 
193 		// return cached DA list from previous discovery
194 		List<String> scopes = DACache.getDiscoverableScopeList(pScopes);
195 		if (scopes != null) {
196 			ResultTable resultTable = new ResultTable();
197 			ServiceRequest srvReq = new ServiceRequest(null, SLPDefaults.DA_SERVICE_TYPE, scopes, null, null);
198 			// multicast DA discovery
199 			DatagramRequester requester = new DatagramRequester(srvReq, resultTable);
200 			requester.start(false);
201 			if (resultTable.hasNext()) {
202 				List<DADescriptor> daList = new ArrayList<DADescriptor>();
203 				while (resultTable.hasNext()) {
204 					try {
205 						daList.add((DADescriptor) resultTable.next());
206 					} catch (RuntimeException e) {
207 						TRC.warning(e.getMessage(), e);
208 					}
209 				}
210 				DACache.setDAList(scopes, daList);
211 			}
212 		}
213 		return getInetAddresses(DACache.getDAList(pScopes));
214 	}
215 
216 	private List<InetAddress> getInetAddresses(List<String> pAddrStrList) {
217 		if (pAddrStrList == null) return null;
218 		List<InetAddress> list = new ArrayList<InetAddress>(pAddrStrList.size());
219 		Iterator<String> strItr = pAddrStrList.iterator();
220 		while (strItr.hasNext()) {
221 			String srvURLStr = strItr.next();
222 			try {
223 				ServiceURL srvURL = new ServiceURL(srvURLStr, ServiceURL.LIFETIME_DEFAULT);
224 				list.add(InetAddress.getByName(srvURL.getURLPath()));
225 			} catch (Exception e) {
226 				TRC.error("Failed to get InetAddress for srvURLStr=" + srvURLStr, e);
227 			}
228 		}
229 		TRC.info("number of discovered DAs:" + list.size());
230 		return list;
231 	}
232 
233 	private void setupUnicasting(List<InetAddress> pDAList) throws IOException {
234 		Iterator<InetAddress> itr = pDAList.iterator();
235 		while (itr.hasNext()) {
236 			InetAddress address = itr.next();
237 			new DatagramRequester(this.iReqMsg, this.iResultTable, address).start(true);
238 		}
239 	}
240 
241 	private void setupMulticasting() throws ServiceLocationException, IOException {
242 		try {
243 			this.iMCastRequester = new DatagramRequester(this.iReqMsg, this.iResultTable);
244 			this.iMCastRequester.start(true);
245 		} catch (UnknownHostException e) {
246 			throw new ServiceLocationException(ServiceLocationException.NETWORK_ERROR, e);
247 		}
248 	}
249 }