/**
* Copyright 2013-2014 Recruit Technologies Co., Ltd. and contributors
* (see CONTRIBUTORS.md)
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. A copy of the
* License is distributed with this work in the LICENSE.md file. You may
* also obtain a copy of the License from
*
* 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.gennai.gungnir.utils;
import static org.gennai.gungnir.tuple.schema.TupleSchema.FieldTypes.*;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.UnknownHostException;
import java.nio.file.DirectoryStream;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
public final class GungnirUtils {
private static final Logger LOG = LoggerFactory.getLogger(GungnirUtils.class);
private static ThreadLocal<Map<String, SimpleDateFormat>> DATE_FORMAT_MAP_THREAD_LOCAL =
new ThreadLocal<Map<String, SimpleDateFormat>>() {
@Override
protected Map<String, SimpleDateFormat> initialValue() {
return Maps.newHashMap();
}
};
private GungnirUtils() {
}
public static Byte toTinyint(Object value) throws TypeCastException {
try {
if (value instanceof String) {
return Byte.parseByte((String) value);
} else if (value instanceof Number) {
return ((Number) value).byteValue();
} else if (value instanceof Boolean) {
return ((Boolean) value) ? (byte) 1 : (byte) 0;
} else if (value instanceof Date) {
return (byte) TimeUnit.MILLISECONDS.toSeconds(((Date) value).getTime());
}
} catch (NumberFormatException e) {
throw new TypeCastException(value, TINYINT.toString());
}
throw new TypeCastException(value, TINYINT.toString());
}
public static Short toSmallint(Object value) throws TypeCastException {
try {
if (value instanceof String) {
return Short.parseShort((String) value);
} else if (value instanceof Number) {
return ((Number) value).shortValue();
} else if (value instanceof Boolean) {
return ((Boolean) value) ? (short) 1 : (short) 0;
} else if (value instanceof Date) {
return (short) TimeUnit.MILLISECONDS.toSeconds(((Date) value).getTime());
}
} catch (NumberFormatException e) {
throw new TypeCastException(value, SMALLINT.toString());
}
throw new TypeCastException(value, SMALLINT.toString());
}
public static Integer toInt(Object value) throws TypeCastException {
try {
if (value instanceof String) {
return Integer.parseInt((String) value);
} else if (value instanceof Number) {
return ((Number) value).intValue();
} else if (value instanceof Boolean) {
return ((Boolean) value) ? (int) 1 : (int) 0;
} else if (value instanceof Date) {
return (int) TimeUnit.MILLISECONDS.toSeconds(((Date) value).getTime());
}
} catch (NumberFormatException e) {
throw new TypeCastException(value, INT.toString());
}
throw new TypeCastException(value, INT.toString());
}
public static Long toBigint(Object value) throws TypeCastException {
try {
if (value instanceof String) {
return Long.parseLong((String) value);
} else if (value instanceof Number) {
return ((Number) value).longValue();
} else if (value instanceof Boolean) {
return ((Boolean) value) ? (long) 1 : (long) 0;
} else if (value instanceof Date) {
return (long) TimeUnit.MILLISECONDS.toSeconds(((Date) value).getTime());
}
} catch (NumberFormatException e) {
throw new TypeCastException(value, BIGINT.toString());
}
throw new TypeCastException(value, BIGINT.toString());
}
public static Float toFloat(Object value) throws TypeCastException {
try {
if (value instanceof String) {
return Float.parseFloat((String) value);
} else if (value instanceof Number) {
return ((Number) value).floatValue();
} else if (value instanceof Boolean) {
return ((Boolean) value) ? (float) 1 : (float) 0;
} else if (value instanceof Date) {
return (float) TimeUnit.MILLISECONDS.toSeconds(((Date) value).getTime());
}
} catch (NumberFormatException e) {
throw new TypeCastException(value, FLOAT.toString());
}
throw new TypeCastException(value, FLOAT.toString());
}
public static Double toDouble(Object value) throws TypeCastException {
try {
if (value instanceof String) {
return Double.parseDouble((String) value);
} else if (value instanceof Number) {
return ((Number) value).doubleValue();
} else if (value instanceof Boolean) {
return ((Boolean) value) ? (double) 1 : (double) 0;
} else if (value instanceof Date) {
return (double) TimeUnit.MILLISECONDS.toSeconds(((Date) value).getTime());
}
} catch (NumberFormatException e) {
throw new TypeCastException(value, DOUBLE.toString());
}
throw new TypeCastException(value, DOUBLE.toString());
}
public static Boolean toBoolean(Object value) {
if (value instanceof String) {
return ((String) value).length() != 0;
} else if (value instanceof Byte) {
return ((Number) value).byteValue() != 0;
} else if (value instanceof Short) {
return ((Number) value).shortValue() != 0;
} else if (value instanceof Integer) {
return ((Number) value).intValue() != 0;
} else if (value instanceof Long) {
return ((Number) value).longValue() != 0;
} else if (value instanceof Float) {
return ((Number) value).floatValue() != 0;
} else if (value instanceof Double) {
return ((Number) value).doubleValue() != 0;
} else if (value instanceof Boolean) {
return ((Boolean) value);
} else if (value instanceof Date) {
return TimeUnit.MILLISECONDS.toSeconds(((Date) value).getTime()) != 0;
}
return false;
}
public static Date toTimestamp(Object value, String dateFormat) throws TypeCastException {
if (dateFormat != null) {
Map<String, SimpleDateFormat> dateFormatMap = DATE_FORMAT_MAP_THREAD_LOCAL.get();
SimpleDateFormat sdf = dateFormatMap.get(dateFormat);
if (sdf == null) {
sdf = new SimpleDateFormat(dateFormat);
dateFormatMap.put(dateFormat, sdf);
}
if (value instanceof String) {
try {
return sdf.parse((String) value);
} catch (ParseException e) {
throw new TypeCastException(value, TIMESTAMP(dateFormat).toString());
}
}
throw new TypeCastException(value, TIMESTAMP(dateFormat).toString());
} else {
try {
if (value instanceof String) {
return new Date(TimeUnit.SECONDS.toMillis(Long.parseLong((String) value)));
} else if (value instanceof Number) {
return new Date(TimeUnit.SECONDS.toMillis(((Number) value).longValue()));
} else if (value instanceof Date) {
return (Date) value;
}
} catch (NumberFormatException e) {
throw new TypeCastException(value, TIMESTAMP.toString());
}
}
throw new TypeCastException(value, TIMESTAMP.toString());
}
public static Date toTimestamp(Object value) throws TypeCastException {
return toTimestamp(value, null);
}
public static Object addition(Object addend, Object augend) throws ArithmeticOperationException {
if (augend != null) {
if (augend instanceof Byte) {
if (addend instanceof Double) {
Double d = ((Double) addend);
d += (Byte) augend;
addend = d;
} else {
Long l = ((Long) addend);
l += (Byte) augend;
addend = l;
}
} else if (augend instanceof Short) {
if (addend instanceof Double) {
Double d = ((Double) addend);
d += (Short) augend;
addend = d;
} else {
Long l = ((Long) addend);
l += (Short) augend;
addend = l;
}
} else if (augend instanceof Integer) {
if (addend instanceof Double) {
Double d = ((Double) addend);
d += (Integer) augend;
addend = d;
} else {
Long l = ((Long) addend);
l += (Integer) augend;
addend = l;
}
} else if (augend instanceof Long) {
if (addend instanceof Double) {
Double d = ((Double) addend);
d += (Long) augend;
addend = d;
} else {
Long l = ((Long) addend);
l += (Long) augend;
addend = l;
}
} else if (augend instanceof Float) {
if (addend instanceof Double) {
Double d = ((Double) addend);
d += (Float) augend;
addend = d;
} else {
Double d = ((Long) addend).doubleValue();
d += (Float) augend;
addend = d;
}
} else if (augend instanceof Double) {
if (addend instanceof Double) {
Double d = ((Double) addend);
d += (Double) augend;
addend = d;
} else {
Double d = ((Long) addend).doubleValue();
d += (Double) augend;
addend = d;
}
} else {
throw new ArithmeticOperationException(
"Values that can be added is only numeric types");
}
}
return addend;
}
public static Object subtraction(Object minuend, Object subtrahend)
throws ArithmeticOperationException {
if (subtrahend != null) {
if (subtrahend instanceof Byte) {
if (minuend instanceof Double) {
Double d = ((Double) minuend);
d -= (Byte) subtrahend;
minuend = d;
} else {
Long l = ((Long) minuend);
l -= (Byte) subtrahend;
minuend = l;
}
} else if (subtrahend instanceof Short) {
if (minuend instanceof Double) {
Double d = ((Double) minuend);
d -= (Short) subtrahend;
minuend = d;
} else {
Long l = ((Long) minuend);
l -= (Short) subtrahend;
minuend = l;
}
} else if (subtrahend instanceof Integer) {
if (minuend instanceof Double) {
Double d = ((Double) minuend);
d -= (Integer) subtrahend;
minuend = d;
} else {
Long l = ((Long) minuend);
l -= (Integer) subtrahend;
minuend = l;
}
} else if (subtrahend instanceof Long) {
if (minuend instanceof Double) {
Double d = ((Double) minuend);
d -= (Long) subtrahend;
minuend = d;
} else {
Long l = ((Long) minuend);
l -= (Long) subtrahend;
minuend = l;
}
} else if (subtrahend instanceof Float) {
if (minuend instanceof Double) {
Double d = ((Double) minuend);
d -= (Float) subtrahend;
minuend = d;
} else {
Double d = ((Long) minuend).doubleValue();
d -= (Float) subtrahend;
minuend = d;
}
} else if (subtrahend instanceof Double) {
if (minuend instanceof Double) {
Double d = ((Double) minuend);
d -= (Double) subtrahend;
minuend = d;
} else {
Double d = ((Long) minuend).doubleValue();
d -= (Double) subtrahend;
minuend = d;
}
} else {
throw new ArithmeticOperationException(
"Values that can be subtracted is only numeric types");
}
}
return minuend;
}
public static ThreadFactory createThreadFactory(String name) {
return new ThreadFactoryBuilder().setNameFormat(name + "-%d")
.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
LOG.error("Uncaugh exception has occurred", e);
}
}).build();
}
public static long currentTimeMillis() {
return System.currentTimeMillis();
}
public static int currentTimeSecs() {
return (int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
}
public static String getLocalAddress() {
String hostAddress = null;
try {
hostAddress = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
hostAddress = "127.0.0.1";
}
if ("127.0.0.1".equals(hostAddress)) {
Enumeration<NetworkInterface> netInterfaces = null;
try {
netInterfaces = NetworkInterface.getNetworkInterfaces();
while (netInterfaces.hasMoreElements()) {
NetworkInterface ni = netInterfaces.nextElement();
Enumeration<InetAddress> ips = ni.getInetAddresses();
while (ips.hasMoreElements()) {
InetAddress ip = ips.nextElement();
if (ip.isSiteLocalAddress()) {
hostAddress = ip.getHostAddress();
}
}
}
} catch (SocketException e) {
return hostAddress;
}
}
return hostAddress;
}
public static void createFatJar(Path srcJar, List<Path> addFiles, Path outputJar)
throws IOException {
Set<String> entries = Sets.newHashSet();
ZipOutputStream jos = null;
byte[] bytes = new byte[8192];
int sz;
try {
jos = new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(outputJar,
StandardOpenOption.CREATE)));
ZipInputStream jis = null;
try {
jis = new ZipInputStream(new BufferedInputStream(Files.newInputStream(srcJar,
StandardOpenOption.READ)));
ZipEntry entry;
while ((entry = jis.getNextEntry()) != null) {
entries.add(entry.getName());
jos.putNextEntry(entry);
while ((sz = jis.read(bytes)) != -1) {
jos.write(bytes, 0, sz);
}
jos.closeEntry();
}
} finally {
if (jis != null) {
jis.close();
}
}
for (Path addFile : addFiles) {
if (addFile.toFile().getName().endsWith(".jar")) {
jis = null;
try {
jis = new ZipInputStream(new BufferedInputStream(Files.newInputStream(addFile,
StandardOpenOption.READ)));
ZipEntry entry;
while ((entry = jis.getNextEntry()) != null) {
if (!entry.getName().startsWith("META-INF") && !entry.getName().endsWith("LICENSE")
&& !entry.getName().endsWith("NOTICE") && !entry.getName().endsWith(".md")) {
if (entries.contains(entry.getName())) {
if (!entry.getName().endsWith("/")) {
throw new IOException("'" + entry.getName() + "' already exists");
}
} else {
jos.putNextEntry(entry);
while ((sz = jis.read(bytes)) != -1) {
jos.write(bytes, 0, sz);
}
jos.closeEntry();
}
}
}
} finally {
if (jis != null) {
jis.close();
}
}
} else {
InputStream is = null;
try {
is = new BufferedInputStream(Files.newInputStream(addFile, StandardOpenOption.READ));
ZipEntry entry = new ZipEntry(addFile.toFile().getName());
jos.putNextEntry(entry);
while ((sz = is.read(bytes)) != -1) {
jos.write(bytes, 0, sz);
}
jos.closeEntry();
} finally {
if (is != null) {
is.close();
}
}
}
}
} catch (IOException e) {
Files.delete(outputJar);
throw e;
} finally {
if (jos != null) {
jos.close();
}
}
}
public static ClassLoader addToClassPath(ClassLoader cloader, List<Path> addPaths) {
URLClassLoader loader = (URLClassLoader) cloader;
List<URL> newPaths = Lists.newArrayList(loader.getURLs());
for (Path addPath : addPaths) {
try {
URL url = addPath.toUri().toURL();
newPaths.add(url);
} catch (MalformedURLException e) {
LOG.error("Failed to add to classpath {}", addPath, e);
}
}
return new URLClassLoader(newPaths.toArray(new URL[0]), loader);
}
public static ClassLoader addToClassPath(Path dir) throws IOException {
if (Files.exists(dir)) {
DirectoryStream<Path> ds = Files.newDirectoryStream(dir);
List<Path> addPaths = Lists.newArrayList(ds);
addPaths.add(dir);
return addToClassPath(Thread.currentThread().getContextClassLoader(), addPaths);
} else {
return null;
}
}
public static void deleteDirectory(Path dir) throws IOException {
if (Files.exists(dir)) {
try {
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
Files.deleteIfExists(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.deleteIfExists(dir);
return FileVisitResult.CONTINUE;
}
});
} catch (NoSuchFileException ignore) {
ignore = null;
}
}
}
public static void createLinkDirectory(Path linkDir, Path dir) throws IOException {
if (!Files.exists(linkDir)) {
Files.createDirectories(linkDir);
}
if (Files.exists(dir)) {
DirectoryStream<Path> ds = Files.newDirectoryStream(dir);
for (Path p : ds) {
Files.createLink(Paths.get(linkDir.toString(), p.toFile().getName()), p);
}
}
}
}