001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  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 implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.commons.settings;
018
019import static org.apache.juneau.commons.utils.AssertionUtils.*;
020import static org.apache.juneau.commons.utils.Utils.*;
021
022import java.util.Optional;
023import java.util.function.*;
024
025import org.apache.juneau.commons.function.ResettableSupplier;
026
027/**
028 * A resettable supplier that provides convenience methods for type conversion.
029 *
030 * <p>
031 * This class extends {@link ResettableSupplier} to provide methods to convert the string value
032 * to various types, similar to the {@link StringSetting#asInteger()}, {@link StringSetting#asBoolean()}, etc. methods.
033 *
034 * <h5 class='section'>Example:</h5>
035 * <p class='bjava'>
036 *    StringSetting <jv>setting</jv> = Settings.<jsf>get</jsf>().setting(<js>"my.property"</js>);
037 *    Setting&lt;Integer&gt; <jv>intValue</jv> = <jv>setting</jv>.asInteger();
038 *    Setting&lt;Boolean&gt; <jv>boolValue</jv> = <jv>setting</jv>.asBoolean();
039 *    Setting&lt;Charset&gt; <jv>charset</jv> = <jv>setting</jv>.asCharset();
040 *
041 *    <jc>// Reset the cache to force recomputation</jc>
042 *    <jv>setting</jv>.reset();
043 * </p>
044 *
045 * @param <T> The type of value supplied.
046 */
047public class Setting<T> extends ResettableSupplier<T> {
048   private final Settings settings;
049
050   /**
051    * Creates a new Setting from a Settings instance and a Supplier.
052    *
053    * @param settings The Settings instance that created this setting. Must not be <jk>null</jk>.
054    * @param supplier The supplier that provides the value. Must not be <jk>null</jk>.
055    */
056   public Setting(Settings settings, Supplier<T> supplier) {
057      super(assertArgNotNull("supplier", supplier));
058      this.settings = assertArgNotNull("settings", settings);
059   }
060
061   /**
062    * Returns the Settings instance that created this setting.
063    *
064    * @return The Settings instance.
065    */
066   public Settings getSettings() {
067      return settings;
068   }
069
070   /**
071    * Returns the underlying Optional&lt;T&gt;.
072    *
073    * <p>
074    * <b>Note:</b> The returned {@link Optional} is a snapshot-in-time of the current value.
075    * Resetting this {@link Setting} will not affect the returned {@link Optional} instance.
076    * To get an updated value after resetting, call this method again.
077    *
078    * @return The optional value.
079    */
080   public Optional<T> asOptional() {
081      return opt(get());
082   }
083
084   /**
085    * If a value is present, applies the provided mapping function to it and returns a Setting describing the result.
086    *
087    * <p>
088    * The returned Setting maintains its own cache, independent of this supplier.
089    * Resetting the mapped supplier does not affect this supplier, and vice versa.
090    *
091    * @param <U> The type of the result of the mapping function.
092    * @param mapper A mapping function to apply to the value, if present. Must not be <jk>null</jk>.
093    * @return A Setting describing the result of applying a mapping function to the value of this Setting, if a value is present, otherwise an empty Setting.
094    */
095   @Override
096   public <U> Setting<U> map(Function<? super T, ? extends U> mapper) {
097      assertArgNotNull("mapper", mapper);
098      return new Setting<>(settings, () -> {
099         T value = get();
100         return nn(value) ? mapper.apply(value) : null;
101      });
102   }
103
104   /**
105    * If a value is present, and the value matches the given predicate, returns a Setting describing the value, otherwise returns an empty Setting.
106    *
107    * <p>
108    * The returned Setting maintains its own cache, independent of this supplier.
109    * Resetting the filtered supplier does not affect this supplier, and vice versa.
110    *
111    * @param predicate A predicate to apply to the value, if present. Must not be <jk>null</jk>.
112    * @return A Setting describing the value of this Setting if a value is present and the value matches the given predicate, otherwise an empty Setting.
113    */
114   @Override
115   public Setting<T> filter(Predicate<? super T> predicate) {
116      assertArgNotNull("predicate", predicate);
117      return new Setting<>(settings, () -> {
118         T value = get();
119         return (nn(value) && predicate.test(value)) ? value : null;
120      });
121   }
122}
123