001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2019 microBean™. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 014 * implied. See the License for the specific language governing 015 * permissions and limitations under the License. 016 */ 017package org.microbean.microprofile.config; 018 019import java.security.AccessController; 020import java.security.PrivilegedAction; 021 022import java.util.AbstractMap.SimpleImmutableEntry; 023import java.util.ArrayList; 024import java.util.Collection; 025import java.util.Collections; 026import java.util.Enumeration; 027import java.util.Iterator; 028import java.util.LinkedHashSet; 029import java.util.Map; 030import java.util.Map.Entry; 031import java.util.NoSuchElementException; 032import java.util.Optional; 033import java.util.Properties; 034import java.util.Set; 035 036import org.eclipse.microprofile.config.Config; 037import org.eclipse.microprofile.config.ConfigProvider; 038 039/** 040 * A {@link Properties} implementation that wraps a {@link Config} and 041 * is suitable for {@linkplain System#setProperties(Properties) 042 * installing as <code>System</code> properties}. 043 * 044 * <p><strong>This class intentionally violates several tenets of the 045 * {@link Map} interface and {@link Properties} class.</strong> 046 * Deviations and oddities are noted below.</p> 047 * 048 * <ul> 049 * 050 * <li>The {@link #clear()} method, while supported, cannot, and 051 * therefore does not, remove any items from the {@link Config} that 052 * is expressed by this class. It will remove all items manually 053 * {@linkplain #put(Object, Object) put} into a {@link 054 * MicroProfileConfigProperties} instance directly.</li> 055 * 056 * <li>Because the MicroProfile Config specification does not say 057 * anything about concurrent access to methods like {@link 058 * Config#getPropertyNames()}, all iteration methods in this class 059 * should be regarded as producing unmodifiable snapshots of a rough 060 * estimate of the keys present in a {@link 061 * MicroProfileConfigProperties} instance.</li> 062 * 063 * <li>All iteration return values are immutable and will throw {@link UnsupportedOperationException} where appropriate.</li> 064 * 065 * <li>Because the MicroProfile Config specification does not say 066 * anything about the underlying dynamic nature of the configuration 067 * systems that a given {@link Config} abstracts, it is possible, for 068 * example, for the {@link #containsKey(Object)} method to return 069 * {@code true}, and then for {@link #get(Object)} to be unable to 070 * retrieve a value.</li> 071 * 072 * <li>Because the MicroProfile Config specification does not say 073 * anything about what implementations must do with regards to caching 074 * or freshness, it is strictly speaking undefined whether fresh or 075 * stale results will be retrieved by instances of this class.</li> 076 * 077 * </ul> 078 * 079 * <h2>Thread Safety</h2> 080 * 081 * <p>This class is safe for concurrent use by multiple threads.</p> 082 * 083 * @author <a href="https://about.me/lairdnelson" 084 * target="_parent">Laird Nelson</a> 085 * 086 * @see Config 087 */ 088public class MicroProfileConfigProperties extends Properties { 089 090 091 /* 092 * Static fields. 093 */ 094 095 096 /** 097 * The version of this class for {@linkplain Serializable 098 * serialization} purposes. 099 */ 100 private static final long serialVersionUID = 1L; 101 102 103 /* 104 * Instance fields. 105 */ 106 107 108 /** 109 * The {@link Config} providing configuration property values. 110 * 111 * <p>This field is never {@code null}.</p> 112 */ 113 private final Config config; 114 115 /** 116 * A flag indicating whether an iteration is in progress; useful to 117 * avoid infinite loops when this {@link 118 * MicroProfileConfigProperties} is {@linkplain 119 * System#setProperties(Properties) installed as <code>System</code> 120 * properties} 121 */ 122 // @GuardedBy("this") 123 private boolean iterating; 124 125 126 /* 127 * Constructors. 128 */ 129 130 131 /** 132 * Creates a new {@link MicroProfileConfigProperties} representing 133 * the {@link Config} that results from {@link 134 * ConfigProvider#getConfig()}. 135 * 136 * @see ConfigProvider#getConfig() 137 */ 138 public MicroProfileConfigProperties() { 139 this(null, null); 140 } 141 142 /** 143 * Creates a new {@link MicroProfileConfigProperties} wrapping the 144 * supplied {@link Config}. 145 * 146 * @param config the {@link Config} to express; may be {@code null} 147 * in which case the return value of {@link 148 * ConfigProvider#getConfig()} will be used instead 149 * 150 * @see ConfigProvider#getConfig() 151 */ 152 public MicroProfileConfigProperties(final Config config) { 153 this(config, null); 154 } 155 156 /** 157 * Creates a new {@link MicroProfileConfigProperties} using the 158 * supplied {@link Properties} as its {@linkplain 159 * Properties#defaults defaults} and wrapping the {@link Config} 160 * that results from {@link ConfigProvider#getConfig()}. 161 * 162 * @param defaults the default {@link Properties}; may be {@code null} 163 * 164 * @see Properties#defaults 165 * 166 * @see ConfigProvider#getConfig() 167 */ 168 public MicroProfileConfigProperties(final Properties defaults) { 169 this(null, defaults); 170 } 171 172 /** 173 * Creates a new {@link MicroProfileConfigProperties} using the 174 * supplied {@link Properties} as its {@linkplain 175 * Properties#defaults defaults} and wrapping the supplied {@link 176 * Config}. 177 * 178 * @param config the {@link Config} to express; may be {@code null} 179 * in which case the return value of {@link 180 * ConfigProvider#getConfig()} will be used instead 181 * 182 * @param defaults the default {@link Properties}; may be {@code 183 * null} 184 * 185 * @see ConfigProvider#getConfig() 186 */ 187 public MicroProfileConfigProperties(final Config config, final Properties defaults) { 188 super(defaults); 189 this.config = config == null ? ConfigProvider.getConfig() : config; 190 } 191 192 193 /* 194 * Instance methods. 195 */ 196 197 198 /** 199 * Returns {@code true} if this {@link MicroProfileConfigProperties} 200 * {@linkplain Properties#containsKey(Object) directly contains} the 201 * supplied {@code key}, or if the supplied {@code key} is a {@link 202 * String} and is contained in the {@link Set} of configuration 203 * property names returned by the {@link Config#getPropertyNames()} 204 * method. 205 * 206 * <h2>Thread Safety</h2> 207 * 208 * <p>This method is safe for concurrent use by multiple 209 * threads.</p> 210 * 211 * @param key the key to seek; may be {@code null} 212 * 213 * @return {@code true} if this {@link MicroProfileConfigProperties} 214 * {@linkplain Properties#containsKey(Object) directly contains} the 215 * supplied {@code key}, or if the supplied {@code key} is a {@link 216 * String} and is contained in the {@link Set} of configuration 217 * property names returned by the {@link Config#getPropertyNames()} 218 * method; {@code false} otherwise 219 */ 220 @Override 221 public synchronized final boolean containsKey(final Object key) { 222 boolean returnValue = super.containsKey(key); 223 if (!returnValue) { 224 final Iterable<?> propertyNames = this.config.getPropertyNames(); 225 if (propertyNames != null) { 226 if (key == null) { 227 for (final Object propertyName : propertyNames) { 228 if (propertyName == null) { 229 returnValue = true; 230 break; 231 } 232 } 233 } else { 234 for (final Object propertyName : propertyNames) { 235 if (key.equals(propertyName)) { 236 returnValue = true; 237 break; 238 } 239 } 240 } 241 } 242 } 243 return returnValue; 244 } 245 246 /** 247 * Invokes the {@link #containsValue(Object)} method with the 248 * supplied {@link Object} and returns the result. 249 * 250 * <h2>Thread Safety</h2> 251 * 252 * <p>This method is safe for concurrent use by multiple 253 * threads.</p> 254 * 255 * @param value the value to seek; may be {@code null} 256 * 257 * @return {@code true} if the {@link #containsValue(Object)} method 258 * returns {@code true}; {@code false} otherwise 259 * 260 * @see #containsValue(Object) 261 */ 262 @Override 263 public synchronized final boolean contains(final Object value) { 264 return this.containsValue(value); 265 } 266 267 /** 268 * Returns {@code true} if this {@link MicroProfileConfigProperties} 269 * contains the supplied value {@link Object}. 270 * 271 * <p>First the {@link Properties#containsValue(Object)} method is 272 * invoked with the supplied {@link Object}. If that returns {@code 273 * true}, then {@code true} is returned.</p> 274 * 275 * <p>Next, {@linkplain Config#getPropertyNames() all known property 276 * names in the <code>Config</code> wrapped by this 277 * <code>MicroProfileConfigProperties</code>} are acquired. This 278 * set is iterated over and {@link Config#getOptionalValue(String, 279 * Class)} is called for each one. If the resulting {@link 280 * Optional} {@linkplain Optional#isPresent() is present}, then 281 * {@code true} is returned.</p> 282 * 283 * <p>In all other cases {@code false} is returned.</p> 284 * 285 * <h2>Thread Safety</h2> 286 * 287 * <p>This method is safe for concurrent use by multiple 288 * threads.</p> 289 * 290 * @param value the value to seek; may be {@code null} 291 * 292 * @return {@code true} if this {@link MicroProfileConfigProperties} 293 * contains the supplied value; {@code false} otherwise 294 * 295 * @see Config#getPropertyNames() 296 * 297 * @see Properties#containsValue(Object) 298 */ 299 @Override 300 public synchronized final boolean containsValue(final Object value) { 301 boolean returnValue = super.containsValue(value); 302 if (!returnValue) { 303 final Iterable<? extends String> propertyNames = this.config.getPropertyNames(); 304 if (propertyNames == null) { 305 returnValue = false; 306 } else { 307 for (final String propertyName : propertyNames) { 308 final Optional<?> propertyValue = this.config.getOptionalValue(propertyName, String.class); 309 if (propertyValue != null && propertyValue.isPresent()) { 310 returnValue = true; 311 break; 312 } 313 } 314 } 315 } 316 return returnValue; 317 } 318 319 /** 320 * Returns the {@link String} value indexed under the supplied 321 * {@code key}. 322 * 323 * <p>This method may return {@code null}.</p> 324 * 325 * <p>This implementation first calls {@link #get(Object)}. If the 326 * result is a non-{@code null} {@link String}, then it is returned. 327 * Otherwise, if the {@link #defaults} field is non-{@code null}, 328 * then {@link Properties#getProperty(String)} is invoked on it with 329 * the supplied {@code key} and the result is returned. In all 330 * other cases {@code null} is returned.</p> 331 * 332 * <h2>Thread Safety</h2> 333 * 334 * <p>This method is safe for concurrent use by multiple 335 * threads.</p> 336 * 337 * @param key the key of the value to return; may be {@code null} 338 * 339 * @return an appropriate value, or {@code null} 340 * 341 * @see #get(Object) 342 * 343 * @see #defaults 344 * 345 * @see Properties#getProperty(String) 346 */ 347 @Override 348 public synchronized final String getProperty(final String key) { 349 final String returnValue; 350 final Object propertyValue = this.get(key); 351 if (propertyValue instanceof String) { 352 returnValue = (String)propertyValue; 353 } else if (this.defaults != null) { 354 returnValue = this.defaults.getProperty(key); 355 } else { 356 returnValue = null; 357 } 358 return returnValue; 359 } 360 361 /** 362 * Returns the value indexed under the supplied {@code key}, or 363 * {@code null} if the value does not exist. Note that a {@code 364 * null} return value could result from a key's being explicitly 365 * mapped to {@code null}, or from a key's absence. 366 * 367 * <p>This implementation first calls {@link 368 * Properties#containsKey(Object)} with the supplied {@code key}. If 369 * that method invocation returns {@code true}, then the {@link 370 * Properties#get(Object)} method is invoked and its result is 371 * returned.</p> 372 * 373 * <p>Otherwise, the {@link Config#getOptionalValue(String, Class)} 374 * method is called and its resulting {@link Optional} result 375 * {@linkplain Optional#get() is acquired} and returned, or, if it 376 * is {@linkplain Optional#isPresent() not present}, {@code null} is 377 * returned.</p> 378 * 379 * <h2>Thread Safety</h2> 380 * 381 * <p>This method is safe for concurrent use by multiple 382 * threads.</p> 383 * 384 * @param key the key of the value to return; may be {@code null} 385 * 386 * @return an appropriate value, or {@code null} 387 * 388 * @see Properties#containsKey(Object) 389 * 390 * @see Properties#get(Object) 391 * 392 * @see Config#getOptionalValue(String, Class) 393 */ 394 @Override 395 public synchronized final Object get(final Object key) { 396 final Object returnValue; 397 if (super.containsKey(key) || this.iterating) { 398 returnValue = super.get(key); 399 } else { 400 this.iterating = true; 401 try { 402 final Optional<String> configValue = this.config.getOptionalValue(key.toString(), String.class); 403 if (configValue == null || !configValue.isPresent()) { 404 returnValue = null; 405 } else { 406 returnValue = configValue.get(); 407 } 408 } finally { 409 iterating = false; 410 } 411 } 412 return returnValue; 413 } 414 415 /** 416 * Returns {@code true} if this {@link MicroProfileConfigProperties} 417 * is empty. In all normal cases, this method will return {@code 418 * false}, since normally {@link Config} instances expose at least 419 * one configuration property value. 420 * 421 * <p>This implementation calls the {@link Properties#isEmpty()} 422 * method. If that method returns {@code false}, then {@code false} 423 * is returned.</p> 424 * 425 * <p>Otherwise this method calls the {@link 426 * Config#getPropertyNames()} method, calls {@link 427 * Iterable#iterator()} on the resulting {@link Iterable}, and, if 428 * it is non-{@code null}, calls the {@link Iterator#hasNext()} 429 * method on it, returning its result.</p> 430 * 431 * <p>In all other cases this method returns {@code true}.</p> 432 * 433 * <p>This method is a much faster way of checking if this {@link 434 * MicroProfileConfigProperties}' size is {@code 0}.</p> 435 * 436 * <h2>Thread Safety</h2> 437 * 438 * <p>This method is safe for concurrent use by multiple 439 * threads.</p> 440 * 441 * @return {@code true}, rarely, if this {@link 442 * MicroProfileConfigProperties} is empty; {@code false} otherwise 443 * 444 * @see Properties#isEmpty() 445 * 446 * @see Config#getPropertyNames() 447 */ 448 @Override 449 public synchronized final boolean isEmpty() { 450 boolean returnValue = super.isEmpty(); 451 if (returnValue) { 452 final Iterable<?> propertyNames = this.config.getPropertyNames(); 453 if (propertyNames != null) { 454 final Iterator<?> iterator = propertyNames.iterator(); 455 returnValue = iterator != null && iterator.hasNext(); 456 } 457 } 458 return returnValue; 459 } 460 461 /** 462 * Returns the size of this {@link MicroProfileConfigProperties} as 463 * expressed by the size of its {@linkplain #keySet() key set}. 464 * 465 * <p>This method returns {@code int}s that are greater than or equal to zero.</p> 466 * 467 * <p>This method rarely returns {@code 0} given the fact that a 468 * {@link Config} normally expresses at least one configuration 469 * property value.</p> 470 * 471 * <p>Use the {@link #isEmpty()} method for a much, much faster way 472 * to check for a size of {@code 0}.</p> 473 * 474 * <h2>Thread Safety</h2> 475 * 476 * <p>This method is safe for concurrent use by multiple 477 * threads.</p> 478 * 479 * @return the size of this {@link MicroProfileConfigProperties} 480 * 481 * @see #keySet() 482 * 483 * @see #isEmpty() 484 */ 485 @Override 486 public synchronized final int size() { 487 return this.keySet().size(); 488 } 489 490 /** 491 * Invokes the {@link #keySet()} method and returns its return 492 * value. 493 * 494 * <p>This method never returns {@code null}.</p> 495 * 496 * <h2>Thread Safety</h2> 497 * 498 * <p>This method is safe for concurrent use by multiple 499 * threads.</p> 500 * 501 * @return the result of invoking the {@link #keySet()} method. 502 * 503 * @see #keySet() 504 */ 505 @Override 506 public synchronized final Enumeration<Object> keys() { 507 return new IteratorEnumeration<>(this.keySet()); 508 } 509 510 /** 511 * Returns a non-{@code null}, {@linkplain 512 * Collections#unmodifiableSet(Set) immutable <code>Set</code>} of 513 * {@link Object}s that contains the keys stored directly by this 514 * {@link MicroProfileConfigProperties} or that are contained in the 515 * return value of a {@link Config#getPropertyNames()} invocation. 516 * 517 * <p>The {@link Set} of {@link Object}s returned by this method is 518 * a disconnected snapshot in time of the keys that were thought to 519 * be in this {@link MicroProfileConfigProperties} at the time the 520 * snapshot was constructed. Changes to this {@link 521 * MicroProfileConfigProperties} are not reflected in the {@link 522 * Set}.</p> 523 * 524 * <h2>Thread Safety</h2> 525 * 526 * <p>This method is safe for concurrent use by multiple 527 * threads.</p> 528 * 529 * <p>The {@link Set} returned by this method is safe for concurrent 530 * use by multiple threads.</p> 531 * 532 * @return a non-{@code null}, {@linkplain 533 * Collections#unmodifiableSet(Set) immutable <code>Set</code>} of 534 * {@link Object}s that contains the keys stored directly by this 535 * {@link MicroProfileConfigProperties} or that are contained in the 536 * return value of a {@link Config#getPropertyNames()} invocation 537 * 538 * @see Properties#keySet() 539 * 540 * @see Config#getPropertyNames() 541 */ 542 @Override 543 public synchronized final Set<Object> keySet() { 544 final Set<Object> returnValue; 545 if (this.iterating) { 546 returnValue = Collections.unmodifiableSet(super.keySet()); 547 } else { 548 this.iterating = true; 549 try { 550 final Iterable<?> configKeys = this.config.getPropertyNames(); 551 if (configKeys == null) { 552 returnValue = Collections.unmodifiableSet(super.keySet()); 553 } else { 554 final Set<Object> keys = new LinkedHashSet<>(); 555 final Set<?> superKeys = super.keySet(); 556 if (superKeys != null && !superKeys.isEmpty()) { 557 keys.addAll(superKeys); 558 } 559 synchronized (configKeys) { 560 for (final Object configKey : configKeys) { 561 keys.add(configKey); 562 } 563 } 564 returnValue = Collections.unmodifiableSet(keys); 565 } 566 } finally { 567 this.iterating = false; 568 } 569 } 570 return returnValue; 571 } 572 573 /** 574 * Returns a non-{@code null} {@link Enumeration} constructed atop 575 * the {@linkplain Collection#iterator() <code>Iterator</code> supplied 576 * by the <code>Collection</code>} returned by an invocation of this 577 * {@link MicroProfileConfigProperties}' {@link #values()} method. 578 * 579 * <h2>Thread Safety</h2> 580 * 581 * <p>This method is safe for concurrent use by multiple 582 * threads.</p> 583 * 584 * @return a non-{@code null} {@link Enumeration} over the values 585 * directly contained by this {@link MicroProfileConfigProperties} 586 * or indirectly accessible via calls to {@link 587 * Config#getOptionalValue(String, Class)} 588 * 589 * @see #values() 590 * 591 * @see Config#getPropertyNames() 592 * 593 * @see Config#getOptionalValue(String, Class) 594 */ 595 @Override 596 public synchronized final Enumeration<Object> elements() { 597 return new IteratorEnumeration<>(this.values()); 598 } 599 600 /** 601 * Returns a non-{@code null}, {@linkplain 602 * Collections#unmodifiableCollection(Collection) immutable 603 * <code>Collection</code>} of this {@link 604 * MicroProfileConfigProperties}' values. 605 * 606 * <p>The values returned are those stored directly (via calls to 607 * {@link #put(Object, Object)}, for example) or stored implicitly 608 * as configuration values accessible via calls to {@link 609 * Config#getOptionalValue(String, Class)}.</p> 610 * 611 * <p>Changes in this {@link MicroProfileConfigProperties} are not 612 * reflected in the returned {@link Collection}.</p> 613 * 614 * <h2>Thread Safety</h2> 615 * 616 * <p>This method is safe for concurrent use by multiple 617 * threads.</p> 618 * 619 * @return a non-{@code null}, {@linkplain 620 * Collections#unmodifiableCollection(Collection) immutable 621 * <code>Collection</code>} of this {@link 622 * MicroProfileConfigProperties}' values 623 * 624 * @see Config#getPropertyNames() 625 * 626 * @see Config#getOptionalValue(String, Class) 627 */ 628 @Override 629 public synchronized final Collection<Object> values() { 630 final Collection<Object> returnValue; 631 if (this.iterating) { 632 returnValue = Collections.unmodifiableCollection(super.values()); 633 } else { 634 this.iterating = true; 635 try { 636 final Iterable<?> configKeys = this.config.getPropertyNames(); 637 if (configKeys == null) { 638 returnValue = Collections.unmodifiableCollection(super.values()); 639 } else { 640 final Collection<Object> values = new ArrayList<>(super.values()); 641 synchronized (configKeys) { 642 for (final Object configKey : configKeys) { 643 final Optional<?> configValue = this.config.getOptionalValue(String.valueOf(configKey), String.class); 644 if (configValue == null || !configValue.isPresent()) { 645 values.add(null); 646 } else { 647 values.add(configValue.get()); 648 } 649 } 650 } 651 returnValue = Collections.unmodifiableCollection(values); 652 } 653 } finally { 654 this.iterating = false; 655 } 656 } 657 return returnValue; 658 } 659 660 /** 661 * Returns a non-{@code null} {@linkplain 662 * Collections#unmodifiableSet(Set) immutable <code>Set</code>} of 663 * {@linkplain SimpleImmutableEntry immutable <code>Entry</code>} 664 * instances representing this {@link MicroProfileConfigProperties}' 665 * entries. 666 * 667 * <p>The entries returned are those that result from calls to 668 * {@link #put(Object, Object)} and similar methods, and from 669 * configuration property values accessible via calls to {@link 670 * Config#getOptionalValue(String, Class)}.</p> 671 * 672 * <p>This method calls the {@link #keySet()} and {@link 673 * #get(Object)} methods. 674 * 675 * <p>Iteration order of the returned {@link Set} is not defined, 676 * with the exception that entries stored directly come at the head 677 * of the returned {@link Set}.</p> 678 * 679 * <h2>Thread Safety</h2> 680 * 681 * <p>This method is safe for concurrent use by multiple 682 * threads.</p> 683 * 684 * @return a non-{@code null} {@linkplain 685 * Collections#unmodifiableSet(Set) immutable <code>Set</code>} of 686 * {@linkplain SimpleImmutableEntry immutable <code>Entry</code>} 687 * instances representing this {@link MicroProfileConfigProperties}' 688 * entries 689 * 690 * @see Config#getPropertyNames() 691 * 692 * @see Config#getOptionalValue(String, Class) 693 */ 694 @Override 695 public synchronized final Set<Entry<Object, Object>> entrySet() { 696 final Set<Entry<Object, Object>> returnValue; 697 final Set<Object> keySet = this.keySet(); 698 if (keySet.isEmpty()) { 699 returnValue = Collections.emptySet(); 700 } else { 701 final Set<Entry<Object, Object>> entrySet = new LinkedHashSet<>(); 702 for (final Object key : keySet) { 703 entrySet.add(new SimpleImmutableEntry<>(key, this.get(key))); 704 } 705 returnValue = Collections.unmodifiableSet(entrySet); 706 } 707 return returnValue; 708 } 709 710 711 /* 712 * Static methods. 713 */ 714 715 716 /** 717 * Installs an instance of {@link MicroProfileConfigProperties} 718 * somewhat irrevocably as {@linkplain 719 * System#setProperties(Properties) the system properties}, with the 720 * current {@linkplain System#getProperties() system properties} as 721 * its defaults. 722 * 723 * <h2>Thread Safety</h2> 724 * 725 * <p>This method is safe for concurrent use by multiple 726 * threads.</p> 727 * 728 * @exception SecurityException if permission is not granted 729 */ 730 public static final void installAsSystemProperties() { 731 AccessController.doPrivileged(new PrivilegedAction<Void>() { 732 @Override 733 public final Void run() { 734 System.setProperties(new MicroProfileConfigProperties(System.getProperties())); 735 return null; 736 } 737 }); 738 } 739 740 741 /* 742 * Inner and nested classes. 743 */ 744 745 746 private static final class IteratorEnumeration<T> implements Enumeration<T>, Iterator<T> { 747 748 private final Iterator<? extends T> iterator; 749 750 private final Enumeration<? extends T> enumeration; 751 752 private IteratorEnumeration(final Iterable<? extends T> iterable) { 753 this(iterable == null ? (Iterator<? extends T>)null : iterable.iterator()); 754 } 755 756 private IteratorEnumeration(final Iterator<? extends T> iterator) { 757 super(); 758 this.iterator = iterator; 759 this.enumeration = null; 760 } 761 762 private IteratorEnumeration(final Enumeration<? extends T> enumeration) { 763 super(); 764 this.iterator = null; 765 this.enumeration = enumeration; 766 } 767 768 @Override 769 public final boolean hasMoreElements() { 770 if (this.enumeration == null) { 771 return this.iterator != null && this.iterator.hasNext(); 772 } else { 773 return this.enumeration.hasMoreElements(); 774 } 775 } 776 777 @Override 778 public final T nextElement() { 779 if (this.enumeration == null) { 780 if (this.iterator == null) { 781 throw new NoSuchElementException(); 782 } 783 return this.iterator.next(); 784 } else { 785 return this.enumeration.nextElement(); 786 } 787 } 788 789 @Override 790 public final boolean hasNext() { 791 if (this.iterator == null) { 792 return this.enumeration != null && this.enumeration.hasMoreElements(); 793 } else { 794 return this.iterator.hasNext(); 795 } 796 } 797 798 @Override 799 public final T next() { 800 if (this.iterator == null) { 801 if (this.enumeration == null) { 802 throw new NoSuchElementException(); 803 } 804 return this.enumeration.nextElement(); 805 } else { 806 return this.iterator.next(); 807 } 808 } 809 810 @Override 811 public void remove() { 812 if (this.iterator == null) { 813 throw new UnsupportedOperationException(); 814 } else { 815 this.iterator.remove(); 816 } 817 } 818 819 } 820 821}