143 hash += names[i].toLowerCase().hashCode() ^ h; |
156 hash += names[i].toLowerCase().hashCode() ^ h; |
144 } |
157 } |
145 return hash; |
158 return hash; |
146 } |
159 } |
147 |
160 |
|
161 /** Match a part of a string against a shell-style pattern. |
|
162 The only pattern characters recognized are <code>?</code>, |
|
163 standing for any one character, |
|
164 and <code>*</code>, standing for any string of |
|
165 characters, including the empty string. For instance, |
|
166 {@code wildmatch("sandwich","sa?d*ch",1,4,1,4)} will match |
|
167 {@code "and"} against {@code "a?d"}. |
|
168 |
|
169 @param str the string containing the sequence to match. |
|
170 @param pat a string containing a pattern to match the sub string |
|
171 against. |
|
172 @param stri the index in the string at which matching should begin. |
|
173 @param strend the index in the string at which the matching should |
|
174 end. |
|
175 @param pati the index in the pattern at which matching should begin. |
|
176 @param patend the index in the pattern at which the matching should |
|
177 end. |
|
178 |
|
179 @return true if and only if the string matches the pattern. |
|
180 */ |
|
181 /* The algorithm is a classical one. We advance pointers in |
|
182 parallel through str and pat. If we encounter a star in pat, |
|
183 we remember its position and continue advancing. If at any |
|
184 stage we get a mismatch between str and pat, we look to see if |
|
185 there is a remembered star. If not, we fail. If so, we |
|
186 retreat pat to just past that star and str to the position |
|
187 after the last one we tried, and we let the match advance |
|
188 again. |
|
189 |
|
190 Even though there is only one remembered star position, the |
|
191 algorithm works when there are several stars in the pattern. |
|
192 When we encounter the second star, we forget the first one. |
|
193 This is OK, because if we get to the second star in A*B*C |
|
194 (where A etc are arbitrary strings), we have already seen AXB. |
|
195 We're therefore setting up a match of *C against the remainder |
|
196 of the string, which will match if that remainder looks like |
|
197 YC, so the whole string looks like AXBYC. |
|
198 */ |
|
199 private static boolean wildmatch(final String str, final String pat, |
|
200 int stri, final int strend, int pati, final int patend) { |
|
201 |
|
202 // System.out.println("matching "+pat.substring(pati,patend)+ |
|
203 // " against "+str.substring(stri, strend)); |
|
204 int starstri; // index for backtrack if "*" attempt fails |
|
205 int starpati; // index for backtrack if "*" attempt fails, +1 |
|
206 |
|
207 starstri = starpati = -1; |
|
208 |
|
209 /* On each pass through this loop, we either advance pati, |
|
210 or we backtrack pati and advance starstri. Since starstri |
|
211 is only ever assigned from pati, the loop must terminate. */ |
|
212 while (true) { |
|
213 if (pati < patend) { |
|
214 final char patc = pat.charAt(pati); |
|
215 switch (patc) { |
|
216 case '?': |
|
217 if (stri == strend) |
|
218 break; |
|
219 stri++; |
|
220 pati++; |
|
221 continue; |
|
222 case '*': |
|
223 pati++; |
|
224 starpati = pati; |
|
225 starstri = stri; |
|
226 continue; |
|
227 default: |
|
228 if (stri < strend && str.charAt(stri) == patc) { |
|
229 stri++; |
|
230 pati++; |
|
231 continue; |
|
232 } |
|
233 break; |
|
234 } |
|
235 } else if (stri == strend) |
|
236 return true; |
|
237 |
|
238 // Mismatched, can we backtrack to a "*"? |
|
239 if (starpati < 0 || starstri == strend) |
|
240 return false; |
|
241 |
|
242 // Retry the match one position later in str |
|
243 pati = starpati; |
|
244 starstri++; |
|
245 stri = starstri; |
|
246 } |
|
247 } |
|
248 |
|
249 /** Match a string against a shell-style pattern. The only pattern |
|
250 characters recognized are <code>?</code>, standing for any one |
|
251 character, and <code>*</code>, standing for any string of |
|
252 characters, including the empty string. |
|
253 |
|
254 @param str the string to match. |
|
255 @param pat the pattern to match the string against. |
|
256 |
|
257 @return true if and only if the string matches the pattern. |
|
258 */ |
|
259 public static boolean wildmatch(String str, String pat) { |
|
260 return wildmatch(str,pat,0,str.length(),0,pat.length()); |
|
261 } |
|
262 |
|
263 /** |
|
264 * Matches a string against a pattern, as a name space path. |
|
265 * This is a special matching where * and ?? don't match //. |
|
266 * The string is split in sub-strings separated by //, and the |
|
267 * pattern is split in sub-patterns separated by //. Each sub-string |
|
268 * is matched against its corresponding sub-pattern. |
|
269 * so <elt-1>//<elt2>//...//<elt-n> matches <pat-1>//<pat-2>//...//<pat-q> |
|
270 * only if n==q and for ( i = 1 => n) elt-i matches pat-i. |
|
271 * |
|
272 * In addition, if we encounter a pattern element which is exactly |
|
273 * **, it can match any number of path-elements - but it must match at |
|
274 * least one element. |
|
275 * When we encounter such a meta-wildcard, we remember its position |
|
276 * and the position in the string path, and we advance both the pattern |
|
277 * and the string. Later, if we encounter a mismatch in pattern & string, |
|
278 * we rewind the position in pattern to just after the meta-wildcard, |
|
279 * and we backtrack the string to i+1 element after the position |
|
280 * we had when we first encountered the meta-wildcard, i being the |
|
281 * position when we last backtracked the string. |
|
282 * |
|
283 * The backtracking logic is an adaptation of the logic in wildmatch |
|
284 * above. |
|
285 * See test/javax/mangement/ObjectName/ApplyWildcardTest.java |
|
286 * |
|
287 * Note: this thing is called 'wild' - and that's for a reason ;-) |
|
288 **/ |
|
289 public static boolean wildpathmatch(String str, String pat) { |
|
290 final int strlen = str.length(); |
|
291 final int patlen = pat.length(); |
|
292 int stri = 0; |
|
293 int pati = 0; |
|
294 |
|
295 int starstri; // index for backtrack if "**" attempt fails |
|
296 int starpati; // index for backtrack if "**" attempt fails |
|
297 |
|
298 starstri = starpati = -1; |
|
299 |
|
300 while (true) { |
|
301 // System.out.println("pati="+pati+", stri="+stri); |
|
302 final int strend = str.indexOf(NAMESPACE_SEPARATOR, stri); |
|
303 final int patend = pat.indexOf(NAMESPACE_SEPARATOR, pati); |
|
304 |
|
305 // no // remaining in either string or pattern: simple wildmatch |
|
306 // until end of string. |
|
307 if (strend == -1 && patend == -1) { |
|
308 // System.out.println("last sub pattern, last sub element..."); |
|
309 // System.out.println("wildmatch("+str.substring(stri,strlen)+ |
|
310 // ","+pat.substring(pati,patlen)+")"); |
|
311 return wildmatch(str,pat,stri,strlen,pati,patlen); |
|
312 } |
|
313 |
|
314 // no // remaining in string, but at least one remaining in |
|
315 // pattern |
|
316 // => no match |
|
317 if (strend == -1) { |
|
318 // System.out.println("pattern has more // than string..."); |
|
319 return false; |
|
320 } |
|
321 |
|
322 // strend is != -1, but patend might. |
|
323 // detect wildcard ** |
|
324 if (patend == pati+2 && pat.charAt(pati)=='*' && |
|
325 pat.charAt(pati+1)=='*') { |
|
326 // if we reach here we know that neither strend nor patend are |
|
327 // equals to -1. |
|
328 stri = strend + NAMESPACE_SEPARATOR_LENGTH; |
|
329 pati = patend + NAMESPACE_SEPARATOR_LENGTH; |
|
330 starpati = pati; // position just after **// in pattern |
|
331 starstri = stri; // we eat 1 element in string, and remember |
|
332 // the position for backtracking and eating |
|
333 // one more element if needed. |
|
334 // System.out.println("starpati="+pati); |
|
335 continue; |
|
336 } |
|
337 |
|
338 // This is a bit hacky: * can match // when // is at the end |
|
339 // of the string, so we include the // delimiter in the pattern |
|
340 // matching. Either we're in the middle of the path, so including |
|
341 // // both at the end of the pattern and at the end of the string |
|
342 // has no effect - match(*//,dfsd//) is equivalent to match(*,dfsd) |
|
343 // or we're at the end of the pattern path, in which case |
|
344 // including // at the end of the string will have the desired |
|
345 // effect (provided that we detect the end of matching correctly, |
|
346 // see further on). |
|
347 // |
|
348 final int endpat = |
|
349 ((patend > -1)?patend+NAMESPACE_SEPARATOR_LENGTH:patlen); |
|
350 final int endstr = |
|
351 ((strend > -1)?strend+NAMESPACE_SEPARATOR_LENGTH:strlen); |
|
352 |
|
353 // if we reach the end of the pattern, or if elt-i & pat-i |
|
354 // don't match, we have a mismatch. |
|
355 |
|
356 // Note: we know that strend != -1, therefore patend==-1 |
|
357 // indicates a mismatch unless pattern can match |
|
358 // a // at the end, and strend+2=strlen. |
|
359 // System.out.println("wildmatch("+str.substring(stri,endstr)+","+ |
|
360 // pat.substring(pati,endpat)+")"); |
|
361 if (!wildmatch(str,pat,stri,endstr,pati,endpat)) { |
|
362 |
|
363 // System.out.println("nomatch"); |
|
364 // if we have a mismatch and didn't encounter any meta-wildcard, |
|
365 // we return false. String & pattern don't match. |
|
366 if (starpati < 0) return false; |
|
367 |
|
368 // If we reach here, we had a meta-wildcard. |
|
369 // We need to backtrack to the wildcard, and make it eat an |
|
370 // additional string element. |
|
371 // |
|
372 stri = str.indexOf(NAMESPACE_SEPARATOR, starstri); |
|
373 // System.out.println("eating one additional element? "+stri); |
|
374 |
|
375 // If there's no more elements to eat, string and pattern |
|
376 // don't match => return false. |
|
377 if (stri == -1) return false; |
|
378 |
|
379 // Backtrack to where we were when we last matched against |
|
380 // the meta-wildcard, make it eat an additional path element, |
|
381 // remember the new positions, and continue from there... |
|
382 // |
|
383 stri = stri + NAMESPACE_SEPARATOR_LENGTH; |
|
384 starstri = stri; |
|
385 pati = starpati; |
|
386 // System.out.println("skiping to stri="+stri); |
|
387 continue; |
|
388 } |
|
389 |
|
390 // Here we know that strend > -1 but we can have patend == -1. |
|
391 // |
|
392 // So if we reach here, we know pat-i+//? has matched |
|
393 // elt-i+// |
|
394 // |
|
395 // If patend==-1, we know that there was no delimiter |
|
396 // at the end of the pattern, that we are at the last pattern, |
|
397 // and therefore that pat-i has matched elt-i+// |
|
398 // |
|
399 // In that case we can consider that we have a match only if |
|
400 // elt-i is also the last path element in the string, which is |
|
401 // equivalent to saying that strend+2==strlen. |
|
402 // |
|
403 if (patend == -1 && starpati == -1) |
|
404 return (strend+NAMESPACE_SEPARATOR_LENGTH==strlen); |
|
405 |
|
406 // patend != -1, or starpati > -1 so there remains something |
|
407 // to match. |
|
408 |
|
409 // go to next pair: elt-(i+1) pat-(i+1); |
|
410 stri = strend + NAMESPACE_SEPARATOR_LENGTH; |
|
411 pati = (patend==-1)?pati:(patend + NAMESPACE_SEPARATOR_LENGTH); |
|
412 } |
|
413 } |
|
414 |
|
415 /** |
|
416 * Returns true if the ObjectName's {@code domain} is selected by the |
|
417 * given {@code pattern}. |
|
418 */ |
|
419 public static boolean isDomainSelected(String domain, String pattern) { |
|
420 if (domain == null || pattern == null) |
|
421 throw new IllegalArgumentException("null"); |
|
422 return Util.wildpathmatch(domain,pattern); |
|
423 } |
|
424 |
148 /** |
425 /** |
149 * Filters a set of ObjectName according to a given pattern. |
426 * Filters a set of ObjectName according to a given pattern. |
150 * |
427 * |
151 * @param pattern the pattern that the returned names must match. |
428 * @param pattern the pattern that the returned names must match. |
152 * @param all the set of names to filter. |
429 * @param all the set of names to filter. |
212 * @return a ClassLoaderRepository that contains the single loader. |
517 * @return a ClassLoaderRepository that contains the single loader. |
213 */ |
518 */ |
214 public static ClassLoaderRepository getSingleClassLoaderRepository( |
519 public static ClassLoaderRepository getSingleClassLoaderRepository( |
215 final ClassLoader loader) { |
520 final ClassLoader loader) { |
216 return new SingleClassLoaderRepository(loader); |
521 return new SingleClassLoaderRepository(loader); |
|
522 } |
|
523 |
|
524 /** |
|
525 * Returns the name of the given MBeanServer that should be put in a |
|
526 * permission you need. |
|
527 * This corresponds to the |
|
528 * {@code *[;mbeanServerName=<mbeanServerName>[;*]]} property |
|
529 * embedded in the MBeanServerId attribute of the |
|
530 * server's {@link MBeanServerDelegate}. |
|
531 * |
|
532 * @param server The MBean server |
|
533 * @return the name of the MBeanServer, or "*" if the name couldn't be |
|
534 * obtained, or {@value MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} |
|
535 * if there was no name. |
|
536 */ |
|
537 public static String getMBeanServerSecurityName(MBeanServer server) { |
|
538 final String notfound = "*"; |
|
539 try { |
|
540 final String mbeanServerId = (String) |
|
541 server.getAttribute(MBeanServerDelegate.DELEGATE_NAME, |
|
542 "MBeanServerId"); |
|
543 final String found = extractMBeanServerName(mbeanServerId); |
|
544 if (found.length()==0) |
|
545 return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME; |
|
546 return found; |
|
547 } catch (Exception x) { |
|
548 logshort("Failed to retrieve MBeanServerName for server, " + |
|
549 "using \"*\"",x); |
|
550 return notfound; |
|
551 } |
|
552 } |
|
553 |
|
554 /** |
|
555 * Returns the name of the MBeanServer embedded in the given |
|
556 * mbeanServerId. If the given mbeanServerId doesn't contain any name, |
|
557 * an empty String is returned. |
|
558 * The MBeanServerId is expected to be of the form: |
|
559 * {@code *[;mbeanServerName=<mbeanServerName>[;*]]} |
|
560 * @param mbeanServerId The MBean server ID |
|
561 * @return the name of the MBeanServer if found, or "" if the name was |
|
562 * not present in the mbeanServerId. |
|
563 */ |
|
564 public static String extractMBeanServerName(String mbeanServerId) { |
|
565 if (mbeanServerId==null) return ""; |
|
566 final String beginMarker=";mbeanServerName="; |
|
567 final String endMarker=";"; |
|
568 final int found = mbeanServerId.indexOf(beginMarker); |
|
569 if (found < 0) return ""; |
|
570 final int start = found + beginMarker.length(); |
|
571 final int stop = mbeanServerId.indexOf(endMarker, start); |
|
572 return mbeanServerId.substring(start, |
|
573 (stop < 0 ? mbeanServerId.length() : stop)); |
|
574 } |
|
575 |
|
576 /** |
|
577 * Insert the given mbeanServerName into the given mbeanServerId. |
|
578 * If mbeanServerName is null, empty, or equals to "-", the returned |
|
579 * mbeanServerId will not contain any mbeanServerName. |
|
580 * @param mbeanServerId The mbeanServerId in which to insert |
|
581 * mbeanServerName |
|
582 * @param mbeanServerName The mbeanServerName |
|
583 * @return an mbeanServerId containing the given mbeanServerName |
|
584 * @throws IllegalArgumentException if mbeanServerId already contains |
|
585 * a different name, or if the given mbeanServerName is not valid. |
|
586 */ |
|
587 public static String insertMBeanServerName(String mbeanServerId, |
|
588 String mbeanServerName) { |
|
589 final String found = extractMBeanServerName(mbeanServerId); |
|
590 if (found.length() > 0 && |
|
591 found.equals(checkServerName(mbeanServerName))) |
|
592 return mbeanServerId; |
|
593 if (found.length() > 0 && !isMBeanServerNameUndefined(found)) |
|
594 throw new IllegalArgumentException( |
|
595 "MBeanServerName already defined"); |
|
596 if (isMBeanServerNameUndefined(mbeanServerName)) |
|
597 return mbeanServerId; |
|
598 final String beginMarker=";mbeanServerName="; |
|
599 return mbeanServerId+beginMarker+checkServerName(mbeanServerName); |
|
600 } |
|
601 |
|
602 /** |
|
603 * Returns true if the given mbeanServerName corresponds to an |
|
604 * undefined MBeanServerName. |
|
605 * The mbeanServerName is considered undefined if it is one of: |
|
606 * {@code null} or {@value MBeanServerFactory#DEFAULT_MBEANSERVER_NAME}. |
|
607 * @param mbeanServerName The mbeanServerName, as returned by |
|
608 * {@link #extractMBeanServerName(String)}. |
|
609 * @return true if the given name corresponds to one of the forms that |
|
610 * denotes an undefined MBeanServerName. |
|
611 */ |
|
612 public static boolean isMBeanServerNameUndefined(String mbeanServerName) { |
|
613 return mbeanServerName == null || |
|
614 MBeanServerFactory.DEFAULT_MBEANSERVER_NAME.equals(mbeanServerName); |
|
615 } |
|
616 /** |
|
617 * Check that the provided mbeanServername is syntactically valid. |
|
618 * @param mbeanServerName An mbeanServerName, or {@code null}. |
|
619 * @return mbeanServerName, or {@value |
|
620 * MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if {@code mbeanServerName} |
|
621 * is {@code null}. |
|
622 * @throws IllegalArgumentException if mbeanServerName contains illegal |
|
623 * characters, or is empty, or is {@code "-"}. |
|
624 * Illegal characters are {@value #ILLEGAL_MBEANSERVER_NAME_CHARS}. |
|
625 */ |
|
626 public static String checkServerName(String mbeanServerName) { |
|
627 if ("".equals(mbeanServerName)) |
|
628 throw new IllegalArgumentException( |
|
629 "\"\" is not a valid MBean server name"); |
|
630 if ("-".equals(mbeanServerName)) |
|
631 throw new IllegalArgumentException( |
|
632 "\"-\" is not a valid MBean server name"); |
|
633 if (isMBeanServerNameUndefined(mbeanServerName)) |
|
634 return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME; |
|
635 for (char c : ILLEGAL_MBEANSERVER_NAME_CHARS.toCharArray()) { |
|
636 if (mbeanServerName.indexOf(c) >= 0) |
|
637 throw new IllegalArgumentException( |
|
638 "invalid character in MBeanServer name: "+c); |
|
639 } |
|
640 return mbeanServerName; |
|
641 } |
|
642 |
|
643 /** |
|
644 * Get the MBeanServer name that should be put in a permission you need. |
|
645 * |
|
646 * @param delegate The MBeanServerDelegate |
|
647 * @return The MBeanServer name - or {@value |
|
648 * MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if there was no name. |
|
649 */ |
|
650 public static String getMBeanServerSecurityName( |
|
651 MBeanServerDelegate delegate) { |
|
652 try { |
|
653 final String serverName = delegate.getMBeanServerName(); |
|
654 if (isMBeanServerNameUndefined(serverName)) |
|
655 return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME; |
|
656 return serverName; |
|
657 } catch (Exception x) { |
|
658 logshort("Failed to retrieve MBeanServerName from delegate, " + |
|
659 "using \"*\"",x); |
|
660 return "*"; |
|
661 } |
|
662 } |
|
663 |
|
664 // Log the exception and its causes without logging the stack trace. |
|
665 // Use with care - it is usally preferable to log the whole stack trace! |
|
666 // We don't want to log the whole stack trace here: logshort() is |
|
667 // called in those cases where the exception might not be abnormal. |
|
668 private static void logshort(String msg, Throwable t) { |
|
669 if (JmxProperties.MISC_LOGGER.isLoggable(Level.FINE)) { |
|
670 StringBuilder toprint = new StringBuilder(msg); |
|
671 toprint.append("\nCaused By: ").append(String.valueOf(t)); |
|
672 while ((t=t.getCause())!=null) |
|
673 toprint.append("\nCaused By: ").append(String.valueOf(t)); |
|
674 JmxProperties.MISC_LOGGER.fine(toprint.toString()); |
|
675 } |
217 } |
676 } |
218 |
677 |
219 public static <T> Set<T> cloneSet(Set<T> set) { |
678 public static <T> Set<T> cloneSet(Set<T> set) { |
220 if (set instanceof SortedSet) { |
679 if (set instanceof SortedSet) { |
221 @SuppressWarnings("unchecked") |
680 @SuppressWarnings("unchecked") |