package ecologylab.bigsemantics; import java.io.BufferedReader; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.Reader; import java.io.StringWriter; import java.nio.charset.Charset; import java.util.Map; import org.apache.commons.configuration.Configuration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Charsets; import com.google.common.hash.HashFunction; import com.google.common.hash.Hashing; import com.google.common.io.BaseEncoding; import ecologylab.generic.StringBuilderBaseUtils; import ecologylab.net.ParsedURL; import ecologylab.serialization.SIMPLTranslationException; import ecologylab.serialization.SimplTypesScope; import ecologylab.serialization.formatenums.StringFormat; /** * Utility functions. * * @author quyin */ public class Utils { private static Logger logger; private static HashFunction fingerprintHashFunc; private static HashFunction secureHashFunc; private static BaseEncoding base64Encoder; private static BaseEncoding base64NoPadding; private static final int BUF_SIZE = 1024; static { logger = LoggerFactory.getLogger(Utils.class); fingerprintHashFunc = Hashing.goodFastHash(32); secureHashFunc = Hashing.sha256(); base64Encoder = BaseEncoding.base64Url(); base64NoPadding = BaseEncoding.base64Url().omitPadding(); } /** * Get the fingerprint of an input string. A fingerprint is not secure hash. And it's not supposed * to be stable (can be different between invocations). * * @param s * @return */ public static byte[] fingerprintBytes(String s) { return fingerprintHashFunc.hashString(s, Charsets.UTF_8).asBytes(); } /** * Get a secure hash of the input string. * * @param s * @return */ public static byte[] secureHashBytes(String s) { return secureHashFunc.hashString(s, Charsets.UTF_8).asBytes(); } /** * Encode the input bytes in base64. * * @param bytes * @return */ public static String base64urlEncode(byte[] bytes) { return base64Encoder.encode(bytes); } /** * Decode base64 string to bytes * * @param string * @return bytes */ public static byte[] base64urlDecode(String input) { return base64Encoder.decode(input); } /** * Base64 encoding, without padding. Since padding info is lost, usually we do not try to decode * the result, thus there is not a corresponding decoding function. * * @param bytes * @return */ public static String base64urlNoPaddingEncode(byte[] bytes) { return base64NoPadding.encode(bytes); } public static String secureHashBase64NoPadding(ParsedURL purl) { return secureHashBase64NoPadding(purl.toString()); } public static String secureHashBase64NoPadding(String purl) { if (purl == null) { return null; } byte[] hash = secureHashBytes(purl); String code = base64urlNoPaddingEncode(hash); return code; } public static String getLocationHash(ParsedURL location) { return "A" + secureHashBase64NoPadding(location); } public static String serializeToString(Object obj, StringFormat format) { if (obj == null) { return null; } try { return SimplTypesScope.serialize(obj, format).toString(); } catch (SIMPLTranslationException e) { logger.error("Cannot serialize " + obj, e); } return "ERROR"; } public static Charset getCharsetByName(String charsetName, Charset defaultCharset) { if (charsetName == null) { return defaultCharset; } try { return Charset.forName(charsetName); } catch (Exception e) { logger.error("Unknown charset: " + charsetName, e); } return defaultCharset; } public static String readInputStream(InputStream inputStream) throws IOException { return readInputStream(inputStream, Charsets.UTF_8); } public static String readInputStream(InputStream inputStream, Charset charset) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, charset)); return readAllFromReader(br); } public static String readAllFromReader(Reader reader) throws IOException { StringBuilder sb = StringBuilderBaseUtils.acquire(); char[] buf = new char[BUF_SIZE]; while (true) { int n = reader.read(buf, 0, BUF_SIZE); if (n < 0) { break; } sb.append(buf, 0, n); } String result = sb.toString(); StringBuilderBaseUtils.release(sb); return result; } public static void writeToFile(File dest, String content) throws IOException { FileWriter fw = null; try { fw = new FileWriter(dest); fw.write(content); } catch (IOException e) { logger.error("Cannot write to file: " + dest, e); throw e; } finally { if (fw != null) { fw.close(); } } } /** * Parse commandline flags from arguments. * * @param flags * The output buffer. * @param args * The commandline arguments. * @return Index to the first element that is not a flag. */ public static int parseCommandlineFlags(Map<String, String> flags, String args[]) { int i = 0; while (i < args.length) { if (args[i].equals("--")) { i += 1; break; } else if (args[i].startsWith("--")) { int p = args[i].indexOf('='); if (p >= 0) { String key = args[i].substring(2, p); String value = args[i].substring(p + 1); flags.put(key, value); } } else { break; } i += 1; } return i; } public static void mergeFlagsToConfigs(Configuration targetConfigs, Map<String, String> flags) { for (String flag : flags.keySet()) { String newValue = flags.get(flag); if (newValue != null) { targetConfigs.setProperty(flag, newValue); } } } public static String getStackTraceAsString(Throwable t) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); t.printStackTrace(pw); String result = sw.toString().replaceAll(System.lineSeparator(), " ").replace("\t", " "); return result; } }