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   * 1892103    2008-02-12  ebak         SLP improvements
18   * 2003590    2008-06-30  blaschke-oss Change licensing from CPL to EPL
19   * 2204488 	  2008-10-28  raman_arora  Fix code to remove compiler warnings
20   * 2524131    2009-01-21  raman_arora  Upgrade client to JDK 1.5 (Phase 1)
21   * 2531371    2009-02-10  raman_arora  Upgrade client to JDK 1.5 (Phase 2)
22   * 2795671    2009-05-22  raman_arora  Add Type to Comparable <T>
23   * 3023120    2010-07-01  blaschke-oss RequestDescriptor equals/compareTo issue
24   * 3023349    2010-07-02  blaschke-oss SLP uses # constructor instead of valueOf
25   */
26  
27  package org.metricshub.wbem.sblim.slp.internal.sa;
28  
29  /*-
30   * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
31   * WBEM Java Client
32   * ჻჻჻჻჻჻
33   * Copyright 2023 - 2025 MetricsHub
34   * ჻჻჻჻჻჻
35   * Licensed under the Apache License, Version 2.0 (the "License");
36   * you may not use this file except in compliance with the License.
37   * You may obtain a copy of the License at
38   *
39   *      http://www.apache.org/licenses/LICENSE-2.0
40   *
41   * Unless required by applicable law or agreed to in writing, software
42   * distributed under the License is distributed on an "AS IS" BASIS,
43   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
44   * See the License for the specific language governing permissions and
45   * limitations under the License.
46   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
47   */
48  
49  import java.net.InetAddress;
50  import java.util.Arrays;
51  import java.util.Date;
52  import java.util.SortedMap;
53  import java.util.TreeMap;
54  import org.metricshub.wbem.sblim.slp.ServiceLocationException;
55  import org.metricshub.wbem.sblim.slp.internal.msg.RequestMessage;
56  import org.metricshub.wbem.sblim.slp.internal.msg.SLPMessage;
57  
58  /**
59   * Keeps track of datagram messages. For requests with the same XID the same
60   * responses should be returned.
61   *
62   */
63  public class MessageTable {
64  
65  	private static class RequestDescriptor implements Comparable<RequestDescriptor> {
66  		private byte[] iSrcAddress;
67  
68  		private byte[] iRequest;
69  
70  		/**
71  		 * Ctor.
72  		 *
73  		 * @param pSource
74  		 * @param pRequest
75  		 * @throws ServiceLocationException
76  		 */
77  		public RequestDescriptor(InetAddress pSource, SLPMessage pRequest) throws ServiceLocationException {
78  			this.iSrcAddress = pSource.getAddress();
79  			this.iRequest =
80  				(pRequest instanceof RequestMessage)
81  					? ((RequestMessage) pRequest).serializeWithoutResponders(false, true, true)
82  					: pRequest.serialize(false, true, true);
83  		}
84  
85  		public int compareTo(RequestDescriptor pObj) {
86  			RequestDescriptor that = pObj;
87  			int cmp = compare(this.iSrcAddress, that.iSrcAddress);
88  			if (cmp != 0) return cmp;
89  			return compare(this.iRequest, that.iRequest);
90  		}
91  
92  		private static int compare(byte[] pBytes0, byte[] pBytes1) {
93  			int len = Math.min(pBytes0.length, pBytes1.length);
94  			for (int i = 0; i < len; i++) {
95  				int cmp = pBytes0[i] & 0xff - pBytes1[i] & 0xff;
96  				if (cmp != 0) return cmp;
97  			}
98  			return pBytes0.length - pBytes1.length;
99  		}
100 
101 		@Override
102 		public boolean equals(Object pObj) {
103 			if (!(pObj instanceof RequestDescriptor)) return false;
104 			RequestDescriptor that = (RequestDescriptor) pObj;
105 			return compare(this.iSrcAddress, that.iSrcAddress) == 0 && compare(this.iRequest, that.iRequest) == 0;
106 		}
107 
108 		@Override
109 		public int hashCode() {
110 			return Arrays.hashCode(this.iSrcAddress) + Arrays.hashCode(this.iRequest);
111 		}
112 	}
113 
114 	private static class TableEntry {
115 		private long iTime;
116 
117 		private RequestDescriptor iReqDesc;
118 
119 		private byte[] iResponse;
120 
121 		/**
122 		 * Ctor.
123 		 *
124 		 * @param pTime
125 		 * @param pReqKey
126 		 * @param pResponse
127 		 */
128 		public TableEntry(long pTime, RequestDescriptor pReqKey, byte[] pResponse) {
129 			this.iTime = pTime;
130 			this.iReqDesc = pReqKey;
131 			this.iResponse = pResponse;
132 		}
133 
134 		/**
135 		 * getTime
136 		 *
137 		 * @return long
138 		 */
139 		public long getTime() {
140 			return this.iTime;
141 		}
142 
143 		/**
144 		 * setTime
145 		 *
146 		 * @param pTime
147 		 */
148 		public void setTime(long pTime) {
149 			this.iTime = pTime;
150 		}
151 
152 		/**
153 		 * getRequestDescriptor
154 		 *
155 		 * @return RequestDescriptor
156 		 */
157 		public RequestDescriptor getRequestDescriptor() {
158 			return this.iReqDesc;
159 		}
160 
161 		/**
162 		 * getResponse
163 		 *
164 		 * @return byte[]
165 		 */
166 		public byte[] getResponse() {
167 			return this.iResponse;
168 		}
169 	}
170 
171 	/**
172 	 * Remember messages for 30 seconds.
173 	 */
174 	private static final long KEEPIN = 30;
175 
176 	/**
177 	 * Time -> TableEntry
178 	 */
179 	private SortedMap<Long, TableEntry> iTimeMap = new TreeMap<Long, TableEntry>();
180 
181 	/**
182 	 * RequestKey -> TableEntry
183 	 */
184 	private SortedMap<RequestDescriptor, TableEntry> iReqMap = new TreeMap<RequestDescriptor, TableEntry>();
185 
186 	/**
187 	 * getResponse
188 	 *
189 	 * @param pSource
190 	 * @param pRequest
191 	 * @return byte[]
192 	 * @throws ServiceLocationException
193 	 */
194 	public synchronized byte[] getResponse(InetAddress pSource, SLPMessage pRequest) throws ServiceLocationException {
195 		long now = getSecs();
196 		RequestDescriptor reqDesc = new RequestDescriptor(pSource, pRequest);
197 		TableEntry entry = this.iReqMap.get(reqDesc);
198 		if (entry == null) return null;
199 		clean();
200 		updateTime(entry, now);
201 		return entry.getResponse();
202 	}
203 
204 	/**
205 	 * addResponse
206 	 *
207 	 * @param pSource
208 	 * @param pRequest
209 	 * @param pRespond
210 	 * @throws ServiceLocationException
211 	 */
212 	public synchronized void addResponse(InetAddress pSource, SLPMessage pRequest, byte[] pRespond)
213 		throws ServiceLocationException {
214 		insert(new TableEntry(getSecs(), new RequestDescriptor(pSource, pRequest), pRespond));
215 		clean();
216 	}
217 
218 	private void clean() {
219 		long now = getSecs();
220 		Long timeStamp;
221 		while ((timeStamp = this.iTimeMap.firstKey()) != null) {
222 			if (now - timeStamp.longValue() < KEEPIN) break;
223 			TableEntry entry = this.iTimeMap.get(timeStamp);
224 			remove(entry);
225 		}
226 	}
227 
228 	private void insert(TableEntry pEntry) {
229 		this.iTimeMap.put(Long.valueOf(pEntry.getTime()), pEntry);
230 		this.iReqMap.put(pEntry.getRequestDescriptor(), pEntry);
231 	}
232 
233 	private void remove(TableEntry pEntry) {
234 		this.iTimeMap.remove(Long.valueOf(pEntry.getTime()));
235 		this.iReqMap.remove(pEntry.getRequestDescriptor());
236 	}
237 
238 	private void updateTime(TableEntry pEntry, long pTime) {
239 		remove(pEntry);
240 		pEntry.setTime(pTime);
241 		insert(pEntry);
242 	}
243 
244 	private static long getSecs() {
245 		return new Date().getTime() / 1000;
246 	}
247 }