/**
* Copyright (C) 2014-2016 LinkedIn Corp. (pinot-core@linkedin.com)
*
* 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.linkedin.pinot.common;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.jar.Attributes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Utils {
private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class);
/**
* Rethrows an exception, even if it is not in the method signature.
*
* @param t The exception to rethrow.
*/
public static void rethrowException(Throwable t) {
/* Error can be thrown anywhere and is type erased on rethrowExceptionInner, making the cast in
rethrowExceptionInner a no-op, allowing us to rethrow the exception without declaring it. */
Utils.<Error>rethrowExceptionInner(t);
}
@SuppressWarnings("unchecked")
private static <T extends Throwable> void rethrowExceptionInner(Throwable exception) throws T {
throw (T) exception;
}
/**
* Obtains the name of the calling method and line number. This is slow, only use this for debugging!
*/
public static String getCallingMethodDetails() {
try {
throw new RuntimeException();
} catch (RuntimeException e) {
return e.getStackTrace()[2].toString();
}
}
private static final AtomicLong _uniqueIdGen = new AtomicLong(1);
public static long getUniqueId() {
return _uniqueIdGen.incrementAndGet();
}
/**
* Takes a string, removes all characters that are not letters or digits and capitalizes the next letter following a
* series of characters that are not letters or digits. For example, toCamelCase("Hello world!") returns "HelloWorld".
*
* @param text The text to camel case
* @return The camel cased version of the string given
*/
public static String toCamelCase(String text) {
int length = text.length();
StringBuilder builder = new StringBuilder(length);
boolean capitalizeNextChar = false;
for (int i = 0; i < length; i++) {
char theChar = text.charAt(i);
if (Character.isLetterOrDigit(theChar) || theChar == '.') {
if (capitalizeNextChar) {
builder.append(Character.toUpperCase(theChar));
capitalizeNextChar = false;
} else {
builder.append(theChar);
}
} else {
capitalizeNextChar = true;
}
}
return builder.toString();
}
/**
* Write the version of Pinot components to the log at info level.
*/
public static void logVersions() {
for (Map.Entry<String, String> titleVersionEntry : getComponentVersions().entrySet()) {
LOGGER.info("Using {} {}", titleVersionEntry.getKey(), titleVersionEntry.getValue());
}
}
/**
* Obtains the version numbers of the Pinot components.
*
* @return A map of component name to component version.
*/
public static Map<String, String> getComponentVersions() {
Map<String, String> componentVersions = new HashMap<>();
// Find the first URLClassLoader, walking up the chain of parent classloaders if necessary
ClassLoader classLoader = Utils.class.getClassLoader();
while (classLoader != null && !(classLoader instanceof URLClassLoader)) {
classLoader = classLoader.getParent();
}
if (classLoader != null) {
URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
URL[] urls = urlClassLoader.getURLs();
for (URL url : urls) {
try {
// Convert the URL to the JAR into a JAR URL: eg. jar:http://www.foo.com/bar/baz.jar!/ in order to load it
URL jarUrl = new URL("jar", "", url + "!/");
URLConnection connection = jarUrl.openConnection();
if (connection instanceof JarURLConnection) {
JarURLConnection jarURLConnection = (JarURLConnection) connection;
// Read JAR attributes and log the Implementation-Title and Implementation-Version manifestvalues for pinot
// components
Attributes attributes = jarURLConnection.getMainAttributes();
if (attributes != null) {
String implementationTitle = attributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
String implementationVersion = attributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
if (implementationTitle != null && implementationTitle.contains("pinot")) {
componentVersions.put(implementationTitle, implementationVersion);
}
}
}
} catch (IOException e) {
// Ignored
}
}
}
return componentVersions;
}
}