package uk.ac.imperial.lsds.seep.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.ac.imperial.lsds.seep.config.ConfigKey;
public class Utils {
final static private Logger LOG = LoggerFactory.getLogger(Utils.class);
public static int SERVER_SOCKET_BACKLOG = 10;
public static String NL = System.getProperty("line.separator");
public static String FILE_URI_SCHEME = "file://";
public static String absolutePath(String resource){
File f = new File(resource);
return f.getAbsolutePath();
}
// FIXME: make this stronger (pass some seed value that gets concatenated to make
// it stronger, concatenating through string and returnning long if necessary
public static int SeepUID() {
return UUID.randomUUID().hashCode();
}
public static int computeIdFromIpAndPort(InetAddress ip, int port){
int hash = 23;
hash = hash * 31 + ip.hashCode();
hash = hash * 31 + port;
return hash;
}
public static int computeIdFromIpAndPort(String ip, int port) {
InetAddress ip2 = null;
try {
ip2 = InetAddress.getByName(ip);
}
catch (UnknownHostException e) {
e.printStackTrace();
}
return ip2.hashCode() + port;
}
public static File writeDataToFile(byte[] serializedFile, String fileName){
FileOutputStream fos;
try {
fos = new FileOutputStream(new File(fileName));
fos.write(serializedFile);
fos.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
//At this point we should have the file on disk
File pathToCode = new File(fileName);
if(!pathToCode.exists()){
return null;
}
return pathToCode;
}
public static byte[] readDataFromFile(String path){
FileInputStream fis = null;
long fileSize = 0;
byte[] data = null;
try {
//Open stream to file
LOG.debug("Opening stream to file: {}", path);
File f = new File(path);
fis = new FileInputStream(f);
fileSize = f.length();
//Read file data
data = new byte[(int)fileSize];
int readBytesFromFile = fis.read(data);
//Check if we have read correctly
if(readBytesFromFile != fileSize){
LOG.warn("Mismatch between read bytes and file size");
fis.close();
return null;
}
//Close the stream
fis.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
finally{
try {
fis.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
return data;
}
public static Properties readPropertiesFromFile(String fileName, String resFileName){
Properties prop = new Properties();
File f = new File(fileName);
try{
InputStream fis = null;
if(f.exists()){
// Read from file
fis = new FileInputStream(new File(fileName));
}
else{
// Read from resource
fis = (InputStream) Thread.currentThread().getContextClassLoader().getResourceAsStream(resFileName);
}
if(fis != null)
prop.load(fis);
}
catch(FileNotFoundException fnfe){
LOG.error("File {} not found while trying to read properties", fileName);
fnfe.printStackTrace();
}
catch(IOException io){
LOG.error("IOException while reading properties", fileName);
io.printStackTrace();
}
return prop;
}
// Default configuration values (so far) can be either INT or STRING
public static boolean isDefaultConfigValue(ConfigKey key1, Object key2) {
switch (key1.type) {
case INT:
if (key2 instanceof Integer)
return (Integer) key1.defaultValue == key2;
else if (key2 instanceof String)
return (Integer) key1.defaultValue == Integer.parseInt((String) key2);
case STRING:
return key1.defaultValue.equals(key2);
default:
return false;
}
}
public static Properties overwriteSecondPropertiesWithFirst(Properties commandLineProperties, Properties fileProperties, List<ConfigKey> configKeys) {
Map<String, ConfigKey> configKeysMap = configKeys.stream().collect(Collectors.toMap(ConfigKey::getName, item -> item));
for(Object key : commandLineProperties.keySet()){
//Case where we have the same property defined both from command line as from file
if( (commandLineProperties.get(key)!= null) && (fileProperties.get(key)!= null) && (configKeysMap.get(key).hasDefault()) ){
//if it is the default => keep the fileproperty - Skipping
if(isDefaultConfigValue( configKeysMap.get(key), commandLineProperties.get(key)))
continue;
}
fileProperties.put(key, commandLineProperties.get(key));
}
return fileProperties;
}
public static InetAddress getIpFromStringRepresentation(String ipStr) {
InetAddress ip = null;
try {
ip = InetAddress.getByName(ipStr);
}
catch (UnknownHostException e) {
e.printStackTrace();
}
return ip;
}
public static String getStringRepresentationOfIp(InetAddress ip){
return ip.getHostAddress();
}
public static InetAddress getLocalIp(){
InetAddress myIp = null;
try {
myIp = InetAddress.getLocalHost();
}
catch (UnknownHostException e) {
e.printStackTrace();
}
return myIp;
}
public static int utf8Length(CharSequence s) {
int count = 0;
for (int i = 0, len = s.length(); i < len; i++) {
char ch = s.charAt(i);
if (ch <= 0x7F) {
count++;
} else if (ch <= 0x7FF) {
count += 2;
} else if (Character.isHighSurrogate(ch)) {
count += 4;
++i;
} else {
count += 3;
}
}
return count;
}
public static <T> T executeComposeFromQuery(String pathToJar, String definitionClass, String[] queryArgs, String methodName) {
Class<?> baseI = null;
Object baseInstance = null;
Method compose = null;
T toReturn = null;
File urlPathToQueryDefinition = new File(pathToJar);
LOG.debug("-> Set path to query definition: {}", urlPathToQueryDefinition.getAbsolutePath());
URL[] urls = new URL[1];
try {
urls[0] = urlPathToQueryDefinition.toURI().toURL();
}
catch (MalformedURLException e) {
e.printStackTrace();
}
// First time it is created we pass the urls
URLClassLoader ucl = new URLClassLoader(urls);
try {
baseI = ucl.loadClass(definitionClass);
// For backwards compatibility, use the default constructor if one with a string array argument is not found
try {
baseInstance = baseI.getConstructor(String[].class).newInstance((Object)queryArgs);
} catch (NoSuchMethodException e) {
baseInstance = baseI.newInstance();
if (queryArgs.length > 0) {
LOG.warn("Query arguments specified but Base class has no constructor taking a String[] argument");
}
}
compose = baseI.getDeclaredMethod(methodName, (Class<?>[])null);
toReturn = (T) compose.invoke(baseInstance, (Object[])null);
// ucl.close();
}
catch (SecurityException e) {
e.printStackTrace();
}
catch (NoSuchMethodException e) {
e.printStackTrace();
}
catch (IllegalArgumentException e) {
e.printStackTrace();
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
catch (InvocationTargetException e) {
e.printStackTrace();
}
catch (InstantiationException e) {
e.printStackTrace();
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
// catch (IOException e) {
// e.printStackTrace();
// }
//Finally we return the queryPlan
return toReturn;
}
public static <K,V> String printMap(Map<K, V> map) {
StringBuffer sb = new StringBuffer();
for(K k : map.keySet()) {
sb.append("K: "+k.toString()+" V: "+map.get(k).toString());
sb.append(Utils.NL);
}
return sb.toString();
}
}