
org.apache.solr.common.util.Utils Maven / Gradle / Ivy
/*
* 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.solr.common.util;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.util.EntityUtils;
import org.apache.solr.client.solrj.cloud.DistribStateManager;
import org.apache.solr.client.solrj.cloud.autoscaling.VersionedData;
import org.apache.solr.client.solrj.impl.BinaryRequestWriter;
import org.apache.solr.common.IteratorWriter;
import org.apache.solr.common.LinkedHashMapWriter;
import org.apache.solr.common.MapWriter;
import org.apache.solr.common.MapWriterMap;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SpecProvider;
import org.apache.solr.common.cloud.SolrZkClient;
import org.apache.solr.common.cloud.ZkOperation;
import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.params.CommonParams;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.server.ByteBufferInputStream;
import org.noggit.CharArr;
import org.noggit.JSONParser;
import org.noggit.JSONWriter;
import org.noggit.ObjectBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.lang.invoke.MethodHandles;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Collections.singletonList;
import static java.util.Collections.unmodifiableList;
import static java.util.Collections.unmodifiableSet;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
public class Utils {
@SuppressWarnings({"rawtypes"})
public static final Function NEW_HASHMAP_FUN = o -> new HashMap<>();
@SuppressWarnings({"rawtypes"})
public static final Function NEW_LINKED_HASHMAP_FUN = o -> new LinkedHashMap<>();
@SuppressWarnings({"rawtypes"})
public static final Function NEW_ATOMICLONG_FUN = o -> new AtomicLong();
@SuppressWarnings({"rawtypes"})
public static final Function NEW_ARRAYLIST_FUN = o -> new ArrayList<>();
@SuppressWarnings({"rawtypes"})
public static final Function NEW_SYNCHRONIZED_ARRAYLIST_FUN = o -> Collections.synchronizedList(new ArrayList<>());
@SuppressWarnings({"rawtypes"})
public static final Function NEW_HASHSET_FUN = o -> new HashSet<>();
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@SuppressWarnings({"rawtypes"})
public static Map getDeepCopy(Map map, int maxDepth) {
return getDeepCopy(map, maxDepth, true, false);
}
@SuppressWarnings({"rawtypes"})
public static Map getDeepCopy(Map map, int maxDepth, boolean mutable) {
return getDeepCopy(map, maxDepth, mutable, false);
}
@SuppressWarnings({"unchecked", "rawtypes"})
public static Map getDeepCopy(Map map, int maxDepth, boolean mutable, boolean sorted) {
if (map == null) return null;
if (maxDepth < 1) return map;
Map copy;
if (sorted) {
copy = new TreeMap<>();
} else {
copy = map instanceof LinkedHashMap ? new LinkedHashMap<>(map.size()) : new HashMap<>(map.size());
}
for (Object o : map.entrySet()) {
Map.Entry e = (Map.Entry) o;
copy.put(e.getKey(), makeDeepCopy(e.getValue(), maxDepth, mutable, sorted));
}
return mutable ? copy : Collections.unmodifiableMap(copy);
}
public static void forEachMapEntry(Object o, String path, @SuppressWarnings({"rawtypes"})BiConsumer fun) {
Object val = Utils.getObjectByPath(o, false, path);
forEachMapEntry(val, fun);
}
public static void forEachMapEntry(Object o, List path, @SuppressWarnings({"rawtypes"})BiConsumer fun) {
Object val = Utils.getObjectByPath(o, false, path);
forEachMapEntry(val, fun);
}
@SuppressWarnings({"unchecked"})
public static void forEachMapEntry(Object o, @SuppressWarnings({"rawtypes"})BiConsumer fun) {
if (o instanceof MapWriter) {
MapWriter m = (MapWriter) o;
try {
m.writeMap(new MapWriter.EntryWriter() {
@Override
public MapWriter.EntryWriter put(CharSequence k, Object v) {
fun.accept(k, v);
return this;
}
});
} catch (IOException e) {
throw new RuntimeException(e);
}
} else if (o instanceof Map) {
((Map) o).forEach((k, v) -> fun.accept(k, v));
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
private static Object makeDeepCopy(Object v, int maxDepth, boolean mutable, boolean sorted) {
if (v instanceof MapWriter && maxDepth > 1) {
v = ((MapWriter) v).toMap(new LinkedHashMap<>());
} else if (v instanceof IteratorWriter && maxDepth > 1) {
v = ((IteratorWriter) v).toList(new ArrayList<>());
if (sorted) {
Collections.sort((List) v);
}
}
if (v instanceof Map) {
v = getDeepCopy((Map) v, maxDepth - 1, mutable, sorted);
} else if (v instanceof Collection) {
v = getDeepCopy((Collection) v, maxDepth - 1, mutable, sorted);
}
return v;
}
public static InputStream toJavabin(Object o) throws IOException {
try (final JavaBinCodec jbc = new JavaBinCodec()) {
BinaryRequestWriter.BAOS baos = new BinaryRequestWriter.BAOS();
jbc.marshal(o, baos);
return new ByteBufferInputStream(ByteBuffer.wrap(baos.getbuf(), 0, baos.size()));
}
}
public static Object fromJavabin(byte[] bytes) throws IOException {
try (JavaBinCodec jbc = new JavaBinCodec()) {
return jbc.unmarshal(bytes);
}
}
@SuppressWarnings({"rawtypes"})
public static Collection getDeepCopy(Collection c, int maxDepth, boolean mutable) {
return getDeepCopy(c, maxDepth, mutable, false);
}
@SuppressWarnings({"unchecked", "rawtypes"})
public static Collection getDeepCopy(Collection c, int maxDepth, boolean mutable, boolean sorted) {
if (c == null || maxDepth < 1) return c;
Collection result = c instanceof Set ?
(sorted ? new TreeSet() : new HashSet()) : new ArrayList();
for (Object o : c) result.add(makeDeepCopy(o, maxDepth, mutable, sorted));
if (sorted && (result instanceof List)) {
Collections.sort((List) result);
}
return mutable ? result : result instanceof Set ? unmodifiableSet((Set) result) : unmodifiableList((List) result);
}
public static void writeJson(Object o, OutputStream os, boolean indent) throws IOException {
writeJson(o, new OutputStreamWriter(os, UTF_8), indent)
.flush();
}
public static Writer writeJson(Object o, Writer writer, boolean indent) throws IOException {
try (SolrJSONWriter jsonWriter = new SolrJSONWriter(writer)) {
jsonWriter.setIndent(indent)
.writeObj(o);
}
return writer;
}
private static class MapWriterJSONWriter extends JSONWriter {
public MapWriterJSONWriter(CharArr out, int indentSize) {
super(out, indentSize);
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public void handleUnknownClass(Object o) {
if (o instanceof MapWriter) {
Map m = ((MapWriter) o).toMap(new LinkedHashMap<>());
write(m);
} else {
super.handleUnknownClass(o);
}
}
}
public static byte[] toJSON(Object o) {
if (o == null) return new byte[0];
CharArr out = new CharArr();
if (!(o instanceof List) && !(o instanceof Map)) {
if (o instanceof MapWriter) {
o = ((MapWriter) o).toMap(new LinkedHashMap<>());
} else if (o instanceof IteratorWriter) {
o = ((IteratorWriter) o).toList(new ArrayList<>());
}
}
new MapWriterJSONWriter(out, 2).write(o); // indentation by default
return toUTF8(out);
}
public static String toJSONString(Object o) {
return new String(toJSON(o), StandardCharsets.UTF_8);
}
public static byte[] toUTF8(CharArr out) {
byte[] arr = new byte[out.size() * 3];
int nBytes = ByteUtils.UTF16toUTF8(out, 0, out.size(), arr, 0);
return Arrays.copyOf(arr, nBytes);
}
public static Object fromJSON(byte[] utf8) {
return fromJSON(utf8, 0, utf8.length);
}
public static Object fromJSON(byte[] utf8, int offset, int length) {
// convert directly from bytes to chars
// and parse directly from that instead of going through
// intermediate strings or readers
CharArr chars = new CharArr();
ByteUtils.UTF8toUTF16(utf8, offset, length, chars);
JSONParser parser = new JSONParser(chars.getArray(), chars.getStart(), chars.length());
parser.setFlags(parser.getFlags() |
JSONParser.ALLOW_MISSING_COLON_COMMA_BEFORE_OBJECT |
JSONParser.OPTIONAL_OUTER_BRACES);
try {
return STANDARDOBJBUILDER.apply(parser).getValStrict();
} catch (IOException e) {
throw new RuntimeException(e); // should never happen w/o using real IO
}
}
public static Map makeMap(Object... keyVals) {
return makeMap(false, keyVals);
}
public static Map makeMap(boolean skipNulls, Object... keyVals) {
if ((keyVals.length & 0x01) != 0) {
throw new IllegalArgumentException("arguments should be key,value");
}
Map propMap = new LinkedHashMap<>(keyVals.length >> 1);
for (int i = 0; i < keyVals.length; i += 2) {
Object keyVal = keyVals[i + 1];
if (skipNulls && keyVal == null) continue;
propMap.put(keyVals[i].toString(), keyVal);
}
return propMap;
}
public static Object fromJSON(InputStream is) {
return fromJSON(new InputStreamReader(is, UTF_8));
}
public static Object fromJSON(Reader is) {
try {
return STANDARDOBJBUILDER.apply(getJSONParser(is)).getValStrict();
} catch (IOException e) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Parse error", e);
}
}
public static final Function STANDARDOBJBUILDER = jsonParser -> {
try {
return new ObjectBuilder(jsonParser);
} catch (IOException e) {
throw new RuntimeException(e);
}
};
public static final Function MAPWRITEROBJBUILDER = jsonParser -> {
try {
return new ObjectBuilder(jsonParser) {
@Override
public Object newObject() {
return new LinkedHashMapWriter<>();
}
};
} catch (IOException e) {
throw new RuntimeException(e);
}
};
public static final Function MAPOBJBUILDER = jsonParser -> {
try {
return new ObjectBuilder(jsonParser) {
@Override
public Object newObject() {
return new HashMap<>();
}
};
} catch (IOException e) {
throw new RuntimeException(e);
}
};
/**
* Util function to convert {@link Object} to {@link String}
* Specially handles {@link Date} to string conversion
*/
public static final Function
© 2015 - 2025 Weber Informatics LLC | Privacy Policy