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.Shorts.*;
020
021import java.util.*;
022import java.util.function.*;
023
024import org.apache.juneau.commons.function.*;
025
026/**
027 * A memoizer that provides convenience methods for type conversion.
028 *
029 * <p>
030 * This class extends {@link Memoizer} to provide methods to convert the string value
031 * to various types, similar to the {@link StringSetting#asInteger()}, {@link StringSetting#asBoolean()}, etc. methods.
032 *
033 * <h5 class='section'>Example:</h5>
034 * <p class='bjava'>
035 *    StringSetting <jv>setting</jv> = Settings.<jsf>get</jsf>().setting(<js>"my.property"</js>);
036 *    Setting&lt;Integer&gt; <jv>intValue</jv> = <jv>setting</jv>.asInteger();
037 *    Setting&lt;Boolean&gt; <jv>boolValue</jv> = <jv>setting</jv>.asBoolean();
038 *    Setting&lt;Charset&gt; <jv>charset</jv> = <jv>setting</jv>.asCharset();
039 *
040 *    <jc>// Reset the cache to force recomputation</jc>
041 *    <jv>setting</jv>.reset();
042 * </p>
043 *
044 * @param <T> The type of value supplied.
045 */
046@SuppressWarnings({
047   "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants
048})
049public class Setting<T> extends Memoizer<T> {
050
051   private final Settings settings;
052
053   /**
054    * Creates a new Setting from a Settings instance and a Supplier.
055    *
056    * @param settings The Settings instance that created this setting. Must not be <jk>null</jk>.
057    * @param supplier The supplier that provides the value. Must not be <jk>null</jk>.
058    */
059   public Setting(Settings settings, Supplier<T> supplier) {
060      super(reqnn("supplier", supplier));
061      this.settings = reqnn("settings", settings);
062   }
063
064   /**
065    * Returns the Settings instance that created this setting.
066    *
067    * @return The Settings instance.
068    */
069   public Settings getSettings() {
070      return settings;
071   }
072
073   /**
074    * Returns the underlying Optional&lt;T&gt;.
075    *
076    * <p>
077    * <b>Note:</b> The returned {@link Optional} is a snapshot-in-time of the current value.
078    * Resetting this {@link Setting} will not affect the returned {@link Optional} instance.
079    * To get an updated value after resetting, call this method again.
080    *
081    * @return The optional value.
082    */
083   public Optional<T> asOptional() {
084      return o(get());
085   }
086
087   /**
088    * If a value is present, applies the provided mapping function to it and returns a Setting describing the result.
089    *
090    * <p>
091    * The returned Setting maintains its own cache, independent of this supplier.
092    * Resetting the mapped supplier does not affect this supplier, and vice versa.
093    *
094    * @param <U> The type of the result of the mapping function.
095    * @param mapper A mapping function to apply to the value, if present. Must not be <jk>null</jk>.
096    * @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.
097    */
098   @Override
099   public <U> Setting<U> map(Function<? super T,? extends U> mapper) {
100      reqnn("mapper", mapper);
101      return new Setting<>(settings, () -> {
102         T value = get();
103         return nn(value) ? mapper.apply(value) : null;
104      });
105   }
106
107   /**
108    * If a value is present, and the value matches the given predicate, returns a Setting describing the value, otherwise returns an empty Setting.
109    *
110    * <p>
111    * The returned Setting maintains its own cache, independent of this supplier.
112    * Resetting the filtered supplier does not affect this supplier, and vice versa.
113    *
114    * @param predicate A predicate to apply to the value, if present. Must not be <jk>null</jk>.
115    * @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.
116    */
117   @Override
118   public Setting<T> filter(Predicate<? super T> predicate) {
119      reqnn("predicate", predicate);
120      return new Setting<>(settings, () -> {
121         T value = get();
122         return (nn(value) && predicate.test(value)) ? value : null;
123      });
124   }
125}
126