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

com.gemstone.gemfire.internal.cache.xmlcache.CacheXmlPropertyResolverHelper Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
 *
 * Licensed 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. See accompanying
 * LICENSE file.
 */

package com.gemstone.gemfire.internal.cache.xmlcache;

import java.util.HashMap;
import java.util.Set;

import com.gemstone.gemfire.i18n.LogWriterI18n;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;

/**
 * Helper class for CacheXmlPropertyResolver. Helps in parsing ${...${}..}..${} strings.
 * 
 * @author Shobhit Agarwal
 * @since 6.6
 */
public class CacheXmlPropertyResolverHelper {

  LogWriterI18n logWriter;

  public static final String DEFAULT_PROPERTY_STRING_PREFIX = "${";

  public static final String DEFAULT_PROPERTY_STRING_SUFFIX = "}";

  public static final String DEFAULT_PREFIX_FOR_SUFFIX = "{";
  /**
   * This HashMap  contains valid suffixes and prefixes to be 
   * parsed by {@link CacheXmlPropertyResolverHelper} like {}, [] or ().
   */
  private static HashMap validSuffixAndPrefixes = new HashMap();

  static {
    validSuffixAndPrefixes.put("}", "{");
    validSuffixAndPrefixes.put("]", "[");
    validSuffixAndPrefixes.put(")", "(");
  }
  /* String specifying the suffice for property key prefix */
  private String propertyPrefix = DEFAULT_PROPERTY_STRING_PREFIX;

  /* String specifying the suffice for property key suffix */
  private String propertySuffix = DEFAULT_PROPERTY_STRING_SUFFIX;

  private String prefixForSuffix = DEFAULT_PREFIX_FOR_SUFFIX;

  /**
   * @param propPrefix
   * @param propSuffix
   */
  public CacheXmlPropertyResolverHelper(String propPrefix,
      String propSuffix) {
    if(propPrefix != null && propSuffix != null){
      String validPrefix = validSuffixAndPrefixes.get(propSuffix);
      if(validPrefix != null && propPrefix.endsWith(validPrefix)){
        this.prefixForSuffix = validPrefix;
      } else {
        this.prefixForSuffix = propPrefix;
      }
      this.propertyPrefix = propPrefix;
      
      this.propertySuffix = propSuffix;
    }
  }

  /**
   * Parses the given string which are supposed to be like ${} for system and/or Gemfire
   * properties to be replaced. This will return property.name from ${property.name}.
   * @param unparsedString
   * @return parsedString
   */
  protected String parseResolvablePropString(String unparsedString, PropertyResolver resolver, Set visitedReplaceableStrings){
    StringBuilder buf = new StringBuilder(unparsedString);
    int prefixIndex = buf.indexOf(propertyPrefix);

    while(prefixIndex != -1){
      int suffixIndex = findSuffixIndex(buf, prefixIndex+propertyPrefix.length());
      if(suffixIndex != -1){
        String replaceableString = buf.substring(prefixIndex+propertyPrefix.length(), suffixIndex);
        //Check for circular references
        if(!visitedReplaceableStrings.add(replaceableString)){
          if(getLogWriter() != null){
            logWriter.info(LocalizedStrings.CacheXmlPropertyResolverHelper_SOME_UNRESOLVED_STRING_REPLACED_CIRCULAR_ERROR__0, replaceableString);
          }
          throw new IllegalArgumentException("Some still unresolved string "+ replaceableString+" was replaced by resolver, leading to circular references.");
        }
        /** Find the replacement using given resolver */
        replaceableString = parseResolvablePropString(replaceableString, resolver, visitedReplaceableStrings);
        String replacement = resolver.resolveReplaceString(replaceableString);

        if(replacement != null){
          /** put replacement in unparsedString and call parseResolvablePropString recursively to find more 
           * unparsedStrings in the replaced value of given unparsedString.*/
          replacement = parseResolvablePropString(replacement, resolver, visitedReplaceableStrings);
          buf.replace(prefixIndex, suffixIndex+propertySuffix.length(), replacement);
          prefixIndex = buf.indexOf(propertyPrefix, prefixIndex+replacement.length());
        } else if(resolver.isIgnoreUnresolvedProperties()) {
          /** Look for more replaceable strings in given unparsedString. */
          prefixIndex = buf.indexOf(propertyPrefix, suffixIndex+propertySuffix.length());
        } else {
          throw new IllegalArgumentException("No replacement found for property : "+ replaceableString);
        }
        //Before iterating again remove replaceable string from visitedReplaceableStrings as it can appear again.
        visitedReplaceableStrings.remove(replaceableString);
      } else {
        prefixIndex = -1;
      }
    }
    
    return buf.toString();
  }

  /**
   * Finds index of suffix in a string from a specified index. Like finds index of
   * "}" in string "${my.prop.name}" starting from index 2, which is 14.
   * @param buf
   * @param index
   * @return suffix
   */
  private int findSuffixIndex(StringBuilder buf, int index) {
    int inNestedProperty = 0;
    while (index < buf.length()) {
      if (buf.substring(index, index+this.propertySuffix.length()).equalsIgnoreCase(this.propertySuffix)) {
        if (inNestedProperty > 0) {
          inNestedProperty--;
          index = index + this.propertySuffix.length();
        } else {
          return index;
        }
      } else if (buf.substring(index, index+this.prefixForSuffix.length()).equalsIgnoreCase(this.prefixForSuffix)) {
        inNestedProperty++;
        index = index + this.prefixForSuffix.length();
      } else {
        index++;
      }
    }
    return -1;
  }

  public LogWriterI18n getLogWriter() {
    return logWriter;
  }

  public void setLogWriter(LogWriterI18n logWriter) {
    this.logWriter = logWriter;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy