blob: 15d03bb1c1557b6c761e2c33c2356117f593a6a4 [file] [log] [blame]
/**
* 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.ratis.util;
import org.apache.ratis.thirdparty.com.google.common.collect.Interner;
import org.apache.ratis.thirdparty.com.google.common.collect.Interners;
import org.apache.ratis.thirdparty.com.google.protobuf.ByteString;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.ByteBuffer;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
public final class StringUtils {
private StringUtils() {
}
public static final String[] EMPTY_STRING_ARRAY = {};
/** Retains a weak reference to each string instance it has interned. */
private static final Interner<String> WEAK_INTERNER = Interners.newWeakInterner();
/**
* Interns and returns a reference to the representative instance
* for any of a collection of string instances that are equal to each other.
* Retains weak reference to the instance,
* and so does not prevent it from being garbage-collected.
*
* @param sample string instance to be interned
* @return weak reference to interned string instance
*/
public static String weakIntern(String sample) {
return sample == null? null: WEAK_INTERNER.intern(sample);
}
/**
* Splits the given comma separated {@link String}.
* Each split value is trimmed.
*
* @param s a comma separated {@link String}, or possibly null.
* @return the split strings, or an empty array if the given string is null.
*/
public static String[] getTrimmedStrings(String s) {
return s == null? EMPTY_STRING_ARRAY
: (s = s.trim()).isEmpty()? EMPTY_STRING_ARRAY
: s.split("\\s*,\\s*");
}
/** The same as String.format(Locale.ENGLISH, format, objects). */
public static String format(final String format, final Object... objects) {
return String.format(Locale.ENGLISH, format, objects);
}
public static String bytes2HexShortString(ByteString bytes) {
final int size = bytes.size();
if (size == 0) {
return "<EMPTY>";
} else if (size > 10) {
// return only the first 10 bytes
return bytes2HexString(bytes.substring(0, 10)) + "...(size=" + size + ")";
} else {
return bytes2HexString(bytes);
}
}
public static String bytes2HexString(ByteString bytes) {
Objects.requireNonNull(bytes, "bytes == null");
return bytes2HexString(bytes.asReadOnlyByteBuffer());
}
public static String bytes2HexString(byte[] bytes) {
Objects.requireNonNull(bytes, "bytes == null");
return bytes2HexString(ByteBuffer.wrap(bytes));
}
public static String bytes2HexString(byte[] bytes, int offset, int length) {
Objects.requireNonNull(bytes, "bytes == null");
return bytes2HexString(ByteBuffer.wrap(bytes, offset, length));
}
public static String bytes2HexString(ByteBuffer bytes) {
Objects.requireNonNull(bytes, "bytes == null");
final StringBuilder s = new StringBuilder(2 * bytes.remaining());
for(; bytes.remaining() > 0; ) {
s.append(format("%02x", bytes.get()));
}
bytes.flip();
return s.toString();
}
public static boolean string2boolean(String s, boolean defaultValue) {
if (s == null || s.isEmpty()) {
return defaultValue;
}
if ("true".equalsIgnoreCase(s)) {
return true;
} else if ("false".equalsIgnoreCase(s)) {
return false;
} else {
return defaultValue;
}
}
public static String stringifyException(Throwable e) {
StringWriter stm = new StringWriter();
PrintWriter wrt = new PrintWriter(stm);
e.printStackTrace(wrt);
wrt.close();
return stm.toString();
}
public static Object stringSupplierAsObject(Supplier<String> supplier) {
return new Object() {
@Override
public String toString() {
return supplier.get();
}
};
}
public static <K, V> String map2String(Map<K, V> map) {
if (map == null) {
return null;
} else if (map.isEmpty()) {
return "<EMPTY_MAP>";
} else {
final StringBuilder b = new StringBuilder("{");
map.entrySet().stream().forEach(e -> b.append("\n ").append(e.getKey()).append(" -> ").append(e.getValue()));
return b.append("\n}").toString();
}
}
public static String completableFuture2String(CompletableFuture<?> future, boolean includeDetails) {
if (!future.isDone()) {
return "NOT_DONE";
} else if (future.isCancelled()) {
return "CANCELLED";
} else if (future.isCompletedExceptionally()) {
if (!includeDetails) {
return "EXCEPTION";
}
return future.thenApply(Objects::toString).exceptionally(Throwable::toString).join();
} else {
if (!includeDetails) {
return "COMPLETED";
}
return "" + future.join();
}
}
}