
com.iofairy.si.SI Maven / Gradle / Ivy
/*
* Copyright (C) 2021 iofairy,
*
* 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.
*/
package com.iofairy.si;
import com.iofairy.except.CircularReferencesException;
import com.iofairy.except.UndefinedVariableException;
import com.iofairy.except.UnexpectedParameterException;
import com.iofairy.except.UnexpectedTypeException;
import com.iofairy.top.G;
import com.iofairy.top.O;
import com.iofairy.top.S;
import com.iofairy.tuple.Tuple;
import java.util.*;
import static com.iofairy.si.SIBase.*;
/**
* String Interpolator. It's not thread-safe.
* 字符串插值器(非线程安全)
*
* @since 0.0.1
*/
public class SI {
private final static int CACHE_SIZE = 1000;
private final static int NESTED_CACHE_SIZE = 500;
private final static int KEY_CACHE_SIZE = 2000;
private final static Map> TEMPLATE_CACHE = Collections.synchronizedMap(new LRUCache<>(CACHE_SIZE));
private final static Map> NESTED_TEMPLATE_CACHE = Collections.synchronizedMap(new LRUCache<>(NESTED_CACHE_SIZE));
private final static Map KEY_CACHE = Collections.synchronizedMap(new LRUCache<>(KEY_CACHE_SIZE));
private final Map valueMap = new HashMap<>(); // 读多写少,未加同步机制
/**
* 是否开启嵌套插值
*/
private boolean enableSIInVariables = false;
/**
* 是否在 {@link #valueMap} 的值中开启嵌套插值({@link #enableSIInVariables} 为 {@code true} 时才有效)
*/
private boolean enableSIInValues = false;
/**
* 是否抛出异常,当 {@link #valueMap} 中不存在指定的变量
*/
private boolean enableUndefinedVariableException = false;
private final static String MSG_UNEXPECTED_PARAM = "This parameter is a key, the key must be end with \" ->\" or \" >>>\" or \" >>\". ";
public SI() {
}
public SI(final Tuple... tuples) {
tuplesPutToMap(tuples);
}
public SI(final Map valueMap) {
if (valueMap != null) this.valueMap.putAll(valueMap);
}
public static SI of(final Tuple... tuples) {
return new SI(tuples);
}
public static SI of(final Map map) {
return new SI(map);
}
/**
* Instantiate an SI object by key-value pairs.
*
* @param kvs key-value pairs
* @return SI object
* @throws RuntimeException if the kvs length not be even.
* @throws NullPointerException if the key is null.
* @throws UnexpectedTypeException if the key is not String.
* @throws UnexpectedParameterException if the key is not end with " ->" or " >>>" or " >>".
* @since 0.0.1
*/
public static SI of(Object... kvs) {
Map kvMap = toMap(false, false, kvs);
return of(kvMap);
}
/**
* Instantiate an SI object by key-value pairs, and key must be end with " ->" or " >>>" or " >>",
* and key will be removed leading and trailing whitespace.
* Examples:
* {@code
* String infoTemplate = "ip: ${ip}---port: ${port}---db: ${db}---otherInfo: ${other_info}";
*
* SI si = SI.init(" ip ->", "127.0.0.1",
* " db ->", "testdb",
* " port ->", 3306,
* " dbType ->", "mysql",
* " other_info ->", Tuple.of("isCluster", true),
* "description ->", new Object());
*
* String dbInfo = si.$(infoTemplate);
* }
*
* @param kvs key-value pairs
* @return SI object
* @throws RuntimeException if the kvs length not be even.
* @throws NullPointerException if the key is null.
* @throws UnexpectedTypeException if the key is not String.
* @throws UnexpectedParameterException if the key is not end with " ->" or " >>>" or " >>".
* @since 0.0.1
*/
public static SI init(Object... kvs) {
Map kvMap = toMap(true, true, kvs);
return of(kvMap);
}
/**
* Instantiate an SI object by key-value pairs, and key must be end with " ->" or " >>>" or " >>".
* Examples:
* {@code
* SI si = SI.load("ip ->", "127.0.0.1",
* "port ->", 3306,
* "db ->", "testdb",
* "dbType ->", "mysql",
* "other_info ->", Tuple.of("isCluster", true),
* "description ->", new Object());
*
* String dbInfo = si.$("ip: ${ip}---port: ${port}---db: ${db}---otherInfo: ${other_info}");
* }
*
* @param kvs key-value pairs
* @return SI object
* @throws RuntimeException if the kvs length not be even.
* @throws NullPointerException if the key is null.
* @throws UnexpectedTypeException if the key is not String.
* @throws UnexpectedParameterException if the key is not end with " ->" or " >>>" or " >>".
* @since 0.0.1
*/
public static SI load(Object... kvs) {
Map kvMap = toMap(true, false, kvs);
return of(kvMap);
}
public SI add(Tuple... tuples) {
tuplesPutToMap(tuples);
return this;
}
public SI add(Map valueMap) {
if (valueMap != null) this.valueMap.putAll(valueMap);
return this;
}
/**
* Add key-value pairs to this SI object.
*
* @param kvs key-value pairs
* @return this SI object
* @throws RuntimeException if the kvs length not be even.
* @throws NullPointerException if the key is null.
* @throws UnexpectedTypeException if the key is not String.
* @since 0.0.1
*/
public SI add(Object... kvs) {
Map kvMap = toMap(false, false, kvs);
return this.add(kvMap);
}
/**
* Fill key-value pairs to this SI object. And key must be end with " ->" or " >>>" or " >>",
* and key will be removed leading and trailing whitespace.
* Examples:
* {@code
* String infoTemplate = "ip: ${ip}---port: ${port}---db: ${db}---otherInfo: ${other_info}";
* SI si = SI.of();
* si.fill(" ip ->", "127.0.0.1",
* " db ->", "testdb",
* " port ->", 3306,
* " dbType ->", "mysql",
* " other_info ->", Tuple.of("isCluster", true),
* "description ->", new Object());
*
* String dbInfo = si.$(infoTemplate);
* }
*
* @param kvs key-value pairs
* @return this SI object
* @throws RuntimeException if the kvs length not be even.
* @throws NullPointerException if the key is null.
* @throws UnexpectedTypeException if the key is not String.
* @throws UnexpectedParameterException if the key is not end with " ->" or " >>>" or " >>".
* @since 0.0.1
*/
public SI fill(Object... kvs) {
Map kvMap = toMap(true, true, kvs);
return this.add(kvMap);
}
public SI set(Tuple... tuples) {
valueMap.clear();
return this.add(tuples);
}
public SI set(Map valueMap) {
this.valueMap.clear();
return this.add(valueMap);
}
/**
* Reset this SI object with key-value pairs.
*
* @param kvs key-value pairs
* @return this SI object
* @throws RuntimeException if the kvs length not be even.
* @throws NullPointerException if the key is null.
* @throws UnexpectedTypeException if the key is not String.
* @since 0.0.1
*/
public SI set(Object... kvs) {
valueMap.clear();
Map kvMap = toMap(false, false, kvs);
return this.add(kvMap);
}
public SI del(String... keys) {
if (keys != null) {
Arrays.stream(keys).forEach(valueMap::remove);
}
return this;
}
private void tuplesPutToMap(Tuple... tuples) {
if (tuples != null) {
Arrays.stream(tuples)
.filter(e -> e != null && e.arity() != 0)
.forEach(t -> valueMap.putAll(t.toMap()));
}
}
/**
* Interpolating for strings.
* 执行插值程序,解析字符串
*
* @param source source string
* @return string that has been processed
* @throws CircularReferencesException when the circular reference occurs
* @throws UndefinedVariableException No variable was found during string interpolation when {@link #enableUndefinedVariableException} is {@code true}.
* @since 0.0.1
*/
public String $(CharSequence source) {
if (source == null) return null;
if (S.isBlank(source)) return source.toString();
String sourceString = source.toString();
StringBuilder interpolated = new StringBuilder();
if (enableSIInVariables) {
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy