| /* |
| * 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.geode.internal.cache.xmlcache; |
| |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.apache.logging.log4j.Logger; |
| |
| import org.apache.geode.annotations.Immutable; |
| import org.apache.geode.logging.internal.log4j.api.LogService; |
| |
| /** |
| * Helper class for CacheXmlPropertyResolver. Helps in parsing ${...${}..}..${} strings. |
| * |
| * @since GemFire 6.6 |
| */ |
| public class CacheXmlPropertyResolverHelper { |
| private static final Logger logger = LogService.getLogger(); |
| |
| 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 <code>HashMap </code> contains valid suffixes and prefixes to be parsed by |
| * {@link CacheXmlPropertyResolverHelper} like {}, [] or (). |
| */ |
| @Immutable |
| private static final Map<String, String> validSuffixAndPrefixes; |
| |
| static { |
| Map<String, String> map = new HashMap<>(); |
| map.put("}", "{"); |
| map.put("]", "["); |
| map.put(")", "("); |
| validSuffixAndPrefixes = Collections.unmodifiableMap(map); |
| } |
| /* 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; |
| |
| 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}. |
| * |
| */ |
| protected String parseResolvablePropString(String unparsedString, PropertyResolver resolver, |
| Set<String> 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)) { |
| logger.info( |
| "Some still unresolved string {} was replaced by resolver, leading to circular references.", |
| replaceableString); |
| throw new IllegalArgumentException("Some still unresolved string " + replaceableString |
| + " was replaced by resolver, leading to circular references."); |
| } |
| /** Find the replacement using given <code>resolver</code> */ |
| replaceableString = |
| parseResolvablePropString(replaceableString, resolver, visitedReplaceableStrings); |
| String replacement = resolver.resolveReplaceString(replaceableString); |
| |
| if (replacement != null) { |
| /** |
| * put replacement in <code>unparsedString</code> and call |
| * <code>parseResolvablePropString</code> 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 <code>unparsedString</code>. */ |
| 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. |
| * |
| */ |
| 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; |
| } |
| } |