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

org.apache.servicecomb.config.inject.PlaceholderResolver Maven / Gradle / Ivy

There is a newer version: 3.2.2
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.servicecomb.config.inject;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.servicecomb.config.ConfigUtil;

/**
 * 
 * not care for performance
 *
 * behavior of multiple list if defined:
 *   org.apache.servicecomb.config.inject.TestPlaceholderResolver#multi_list()
 * behavior of nested and multiple list variable is undefined
 *   org.apache.servicecomb.config.inject.TestPlaceholderResolver#mixed()
 * 
*/ public class PlaceholderResolver { private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("(?\\\\)?\\$\\{(?[^{}]+)\\}"); static class SplitPart { boolean var; String fullName; Object value; public SplitPart(boolean var, String fullName) { this.var = var; this.fullName = fullName; } @Override public String toString() { return "SplitPart{" + "var=" + var + ", fullName='" + fullName + '\'' + ", value=" + value + '}'; } } static class Row { List parts = new ArrayList<>(); int cartesianProductCount = 1; int varCount = 0; } public String replaceFirst(String str) { return replace(str, Collections.emptyMap()).get(0); } public String replaceFirst(String str, Map parameters) { return replace(str, parameters).get(0); } public List replace(String str, Map parameters) { List finalRows = replaceToRows(str, parameters); List replaced = new ArrayList<>(); for (Row row : finalRows) { resolve(row, replaced); } replaced.replaceAll(s -> s.replace("\\$", "$")); return replaced; } private List replaceToRows(String str, Map parameters) { List finalRows = new ArrayList<>(); List remainRows = new ArrayList<>(); replaceToRows(str, parameters, remainRows, finalRows); for (String row : remainRows) { List nestedRows = replaceToRows(row, parameters); finalRows.addAll(nestedRows); } return finalRows; } private void replaceToRows(String str, Map parameters, List remainRows, List finalRows) { Row row = parseToRow(str, parameters); if (row.varCount == 0 && row.cartesianProductCount == 1) { finalRows.add(row); return; } resolve(row, remainRows); } private Row parseToRow(String str, Map parameters) { Matcher matcher = PLACEHOLDER_PATTERN.matcher(str); Row row = new Row(); int last = 0; while (matcher.find()) { row.parts.add(new SplitPart(false, str.substring(last, matcher.start()))); last = matcher.end(); if (matcher.group("escape") != null) { row.parts.add(new SplitPart(false, matcher.group().substring(1))); continue; } String name = matcher.group("name"); Object value = findValue(parameters, name); if (value instanceof Collection) { row.cartesianProductCount *= ((Collection) value).size(); } if (value != null) { row.varCount++; } SplitPart splitPart = new SplitPart(value != null, matcher.group()); splitPart.value = value; row.parts.add(splitPart); } row.parts.add(new SplitPart(false, str.substring(last))); return row; } // resolve placeholder and execute cartesian product @SuppressWarnings("unchecked") private void resolve(Row row, List resolvedRows) { List stringBuilders = new ArrayList<>(); for (int idx = 0; idx < row.cartesianProductCount; idx++) { stringBuilders.add(new StringBuilder()); } int collectionRepeatCount = 1; for (SplitPart part : row.parts) { if (!part.var) { for (int idx = 0; idx < row.cartesianProductCount; idx++) { StringBuilder sb = stringBuilders.get(idx); if (part.fullName.startsWith("$")) { sb.append("\\" + part.fullName); continue; } sb.append(part.fullName); } continue; } if (part.value instanceof Collection) { int size = ((Collection) part.value).size(); int rowRepeatCount = row.cartesianProductCount / size / collectionRepeatCount; int valueIdx = 0; for (int collectionRepeatIdx = 0; collectionRepeatIdx < collectionRepeatCount; collectionRepeatIdx++) { for (String value : (Collection) part.value) { for (int repeatIdx = 0; repeatIdx < rowRepeatCount; repeatIdx++) { StringBuilder sb = stringBuilders.get(valueIdx); valueIdx++; sb.append(value); } } } collectionRepeatCount *= size; continue; } // normal var for (int idx = 0; idx < row.cartesianProductCount; idx++) { StringBuilder sb = stringBuilders.get(idx); sb.append(part.value); } } for (StringBuilder sb : stringBuilders) { resolvedRows.add(sb.toString()); } } private Object findValue(Map parameters, String key) { Object value = parameters.get(key); if (value == null) { value = ConfigUtil.getProperty(key); } return value; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy