All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.phoenix.util.ReadOnlyProps Maven / Gradle / Ivy

There is a newer version: 4.15.0-HBase-1.5
Show newest version
/*
 * 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.phoenix.util;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Nonnull;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Objects;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Maps;

/**
 * 
 * Read-only properties that avoids unnecessary synchronization in
 * java.util.Properties.
 *
 */
public class ReadOnlyProps implements Iterable> {
    private static final Logger logger = LoggerFactory.getLogger(ReadOnlyProps.class);
    public static final ReadOnlyProps EMPTY_PROPS = new ReadOnlyProps();
    @Nonnull
    private final Map props;
    @Nonnull
    private final Map overrideProps;
    
    public ReadOnlyProps(ReadOnlyProps defaultProps, Iterator> iterator) {
        Map map = new HashMap(defaultProps.asMap());
        while (iterator.hasNext()) {
            Entry entry = iterator.next();
            map.put(entry.getKey(), entry.getValue());
        }
        this.props = ImmutableMap.copyOf(map);
        this.overrideProps = ImmutableMap.of();
    }

    public ReadOnlyProps(Iterator> iterator) {
        this(EMPTY_PROPS, iterator);
    }

    private ReadOnlyProps() {
        this.props = ImmutableMap.of();
        this.overrideProps = ImmutableMap.of();
    }

    public ReadOnlyProps(Map props) {
        this.props = ImmutableMap.copyOf(props);
        this.overrideProps = ImmutableMap.of();
    }

    private ReadOnlyProps(ReadOnlyProps defaultProps, Properties overridesArg) {
        this.props = defaultProps.props;
        if (overridesArg == null || overridesArg.isEmpty()) {
            this.overrideProps = defaultProps.overrideProps;
        } else {
            Map combinedOverrides =
                    Maps.newHashMapWithExpectedSize(defaultProps.overrideProps.size()
                            + overridesArg.size());
            if (!defaultProps.overrideProps.isEmpty()) {
                combinedOverrides.putAll(defaultProps.overrideProps);
            }
            for (Entry entry : overridesArg.entrySet()) {
                combinedOverrides.put(entry.getKey().toString(), entry.getValue().toString());
            }
            this.overrideProps = ImmutableMap.copyOf(combinedOverrides);
        }
    }

    private static Pattern varPat = Pattern.compile("\\$\\{[^\\}\\$\u0020]+\\}");
    private static int MAX_SUBST = 20;

    private String substituteVars(String expr) {
        if (expr == null) {
          return null;
        }
        Matcher match = varPat.matcher("");
        String eval = expr;
        for(int s=0; sname property, without doing
     * variable expansion.
     * 
     * @param name the property name.
     * @return the value of the name property, 
     *         or null if no such property exists.
     */
    public String getRaw(String name) {
      String overridenValue = overrideProps.get(name);
      return overridenValue == null ? props.get(name) : overridenValue;
    }

    public String getRaw(String name, String defaultValue) {
        String value = getRaw(name);
        if (value == null) {
            return defaultValue;
        }
        return value;
      }

    /** 
     * Get the value of the name property. If no such property 
     * exists, then defaultValue is returned.
     * 
     * @param name property name.
     * @param defaultValue default value.
     * @return property value, or defaultValue if the property 
     *         doesn't exist.                    
     */
    public String get(String name, String defaultValue) {
      return substituteVars(getRaw(name, defaultValue));
    }
      
    /**
     * Get the value of the name property, null if
     * no such property exists.
     * 
     * Values are processed for variable expansion 
     * before being returned. 
     * 
     * @param name the property name.
     * @return the value of the name property, 
     *         or null if no such property exists.
     */
    public String get(String name) {
      return substituteVars(getRaw(name));
    }

    private String getHexDigits(String value) {
        boolean negative = false;
        String str = value;
        String hexString = null;
        if (value.startsWith("-")) {
          negative = true;
          str = value.substring(1);
        }
        if (str.startsWith("0x") || str.startsWith("0X")) {
          hexString = str.substring(2);
          if (negative) {
            hexString = "-" + hexString;
          }
          return hexString;
        }
        return null;
      }
      
    /** 
     * Get the value of the name property as a boolean.  
     * If no such property is specified, or if the specified value is not a valid
     * boolean, then defaultValue is returned.
     * 
     * @param name property name.
     * @param defaultValue default value.
     * @return property value as a boolean, 
     *         or defaultValue. 
     */
    public boolean getBoolean(String name, boolean defaultValue) {
      String valueString = get(name);
      if ("true".equals(valueString))
        return true;
      else if ("false".equals(valueString))
        return false;
      else return defaultValue;
    }

    /** 
     * Get the value of the name property as an int.
     *   
     * If no such property exists, or if the specified value is not a valid
     * int, then defaultValue is returned.
     * 
     * @param name property name.
     * @param defaultValue default value.
     * @return property value as an int, 
     *         or defaultValue. 
     */
    public int getInt(String name, int defaultValue) {
      String valueString = get(name);
      if (valueString == null)
        return defaultValue;
      try {
        String hexString = getHexDigits(valueString);
        if (hexString != null) {
          return Integer.parseInt(hexString, 16);
        }
        return Integer.parseInt(valueString);
      } catch (NumberFormatException e) {
        return defaultValue;
      }
    }
    
    /** 
     * Get the value of the name property as a long.  
     * If no such property is specified, or if the specified value is not a valid
     * long, then defaultValue is returned.
     * 
     * @param name property name.
     * @param defaultValue default value.
     * @return property value as a long, 
     *         or defaultValue. 
     */
    public long getLong(String name, long defaultValue) {
      String valueString = get(name);
      if (valueString == null)
        return defaultValue;
      try {
        String hexString = getHexDigits(valueString);
        if (hexString != null) {
          return Long.parseLong(hexString, 16);
        }
        return Long.parseLong(valueString);
      } catch (NumberFormatException e) {
        return defaultValue;
      }
    }

    /** 
     * Get the value of the name property as a float.  
     * If no such property is specified, or if the specified value is not a valid
     * float, then defaultValue is returned.
     * 
     * @param name property name.
     * @param defaultValue default value.
     * @return property value as a float, 
     *         or defaultValue. 
     */
    public float getFloat(String name, float defaultValue) {
      String valueString = get(name);
      if (valueString == null)
        return defaultValue;
      try {
        return Float.parseFloat(valueString);
      } catch (NumberFormatException e) {
        return defaultValue;
      }
    }

    /**
     * Get the properties as a Map
     * 
     * @return Map 
     */
    public Map asMap() {
        return props;
    }
    
    @Override
    public Iterator> iterator() {
        return props.entrySet().iterator();
    }
    
    public boolean isEmpty() {
        return props.isEmpty();
    }

    /**
     * Constructs new map only if necessary for adding the override properties.
     * @param overrides Map of properties to override current properties.
     * @return new ReadOnlyProps if in applying the overrides there are
     * modifications to the current underlying Map, otherwise returns this.
     */
    public ReadOnlyProps addAll(Properties overrides) {
        for (Entry entry : overrides.entrySet()) {
            String key = entry.getKey().toString();
            String value = entry.getValue().toString();
            String oldValue = props.get(key);
            if (!Objects.equal(oldValue, value)) {
                if (logger.isDebugEnabled()) logger.debug("Creating new ReadOnlyProps due to " + key + " with " + oldValue + "!=" + value);
                return new ReadOnlyProps(this, overrides);
            }
        }
        return this;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy