content: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to you under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.calcite.util;
  
  import org.apache.calcite.runtime.Resources;
  import org.apache.calcite.runtime.Resources.BooleanProp;
  import org.apache.calcite.runtime.Resources.Default;
  import org.apache.calcite.runtime.Resources.IntProp;
  import org.apache.calcite.runtime.Resources.Resource;
  import org.apache.calcite.runtime.Resources.StringProp;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.util.Collections;
  import java.util.Properties;
  
  import static java.util.Objects.requireNonNull;
  
  /**
   * Provides an environment for debugging information, et cetera, used by
   * saffron.
   *
   * <p>It is a singleton, accessed via the {@link #INSTANCE} object. It is
   * populated from System properties if saffron is invoked via a <code>
   * main()</code> method, from a <code>javax.servlet.ServletContext</code> if
   * saffron is invoked from a servlet, and so forth. If there is a file called
   * <code>"saffron.properties"</code> in the current directory, it is read too.
   *
   * <p>Every property used in saffron code must have a method in this interface.
   * The method must return a sub-class of
   * {@link org.apache.calcite.runtime.Resources.Prop}. The javadoc
   * comment must describe the name of the property (for example,
   * "net.sf.saffron.connection.PoolSize") and the default value, if any. <em>
   * Developers, please make sure that this remains so!</em>
   *
   * @deprecated As of release 1.19,
   * replaced by {@link org.apache.calcite.config.CalciteSystemProperty}
   */
  @Deprecated
  public interface SaffronProperties {
    /**
     * The boolean property "saffron.opt.allowInfiniteCostConverters" determines
     * whether the optimizer will consider adding converters of infinite cost in
     * order to convert a relational expression from one calling convention to
     * another. The default value is <code>true</code>.
     */
    @Resource("saffron.opt.allowInfiniteCostConverters")
    @Default("true")
    BooleanProp allowInfiniteCostConverters();
  
    /**
     * The string property "saffron.default.charset" is the name of the default
     * character set. The default is "ISO-8859-1". It is used in
     * {@link org.apache.calcite.sql.validate.SqlValidator}.
     */
    @Resource("saffron.default.charset")
    @Default("ISO-8859-1")
    StringProp defaultCharset();
  
    /**
     * The string property "saffron.default.nationalcharset" is the name of the
     * default national character set which is used with the N'string' construct
     * which may or may not be different from the {@link #defaultCharset}. The
     * default is "ISO-8859-1". It is used in
     * {@link org.apache.calcite.sql.SqlLiteral#SqlLiteral}
     */
    @Resource("saffron.default.nationalcharset")
    @Default("ISO-8859-1")
    StringProp defaultNationalCharset();
  
    /**
     * The string property "saffron.default.collation.name" is the name of the
     * default collation. The default is "ISO-8859-1$en_US". Used in
     * {@link org.apache.calcite.sql.SqlCollation} and
     * {@link org.apache.calcite.sql.SqlLiteral#SqlLiteral}
     */
    @Resource("saffron.default.collation.name")
    @Default("ISO-8859-1$en_US")
    StringProp defaultCollation();
  
    /**
     * The string property "saffron.default.collation.strength" is the strength
     * of the default collation. The default is "primary". Used in
     * {@link org.apache.calcite.sql.SqlCollation} and
     * {@link org.apache.calcite.sql.SqlLiteral#SqlLiteral}
     */
    @Resource("saffron.default.collation.strength")
    @Default("primary")
    StringProp defaultCollationStrength();
  
    /**
     * The string property "saffron.metadata.handler.cache.maximum.size" is the
     * maximum size of the cache of metadata handlers. A typical value is
     * the number of queries being concurrently prepared multiplied by the number
     * of types of metadata.
     *
     * <p>If the value is less than 0, there is no limit. The default is 1,000.
     */
    @Resource("saffron.metadata.handler.cache.maximum.size")
    @Default("1000")
    IntProp metadataHandlerCacheMaximumSize();
  
    SaffronProperties INSTANCE = Helper.instance();
  
    /** Helper class. */
    class Helper {
      private Helper() {}
  
      /**
       * Retrieves the singleton instance of {@link SaffronProperties}.
       */
      static SaffronProperties instance() {
        Properties properties = new Properties();
  
        // Read properties from the file "saffron.properties", if it exists in
        // classpath.
        try (InputStream stream =
                 requireNonNull(Helper.class.getClassLoader(), "classLoader")
                     .getResourceAsStream("saffron.properties")) {
          if (stream != null) {
            properties.load(stream);
          }
        } catch (IOException e) {
          throw new RuntimeException("while reading saffron.properties file", e);
        } catch (SecurityException ignore) {
          // Ignore SecurityException on purpose because if
          // we can't get to the file we fall through.
        }
  
        // copy in all system properties which start with "saffron."
        Properties source = System.getProperties();
        for (Object objectKey : Collections.list(source.keys())) {
          String key = (String) objectKey;
          String value =
              requireNonNull(source.getProperty(key),
                  () -> "value for " + key);
          if (key.startsWith("saffron.") || key.startsWith("net.sf.saffron.")) {
            properties.setProperty(key, value);
          }
        }
        return Resources.create(properties, SaffronProperties.class);
      }
    }
  }
  