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}