/*
* ProActive Parallel Suite(TM):
* The Open Source library for parallel and distributed
* Workflows & Scheduling, Orchestration, Cloud Automation
* and Big Data Analysis on Enterprise Grids & Clouds.
*
* Copyright (c) 2007 - 2017 ActiveEon
* Contact: contact@activeeon.com
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation: version 3 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* If needed, contact us to obtain a release under GPL Version 2 or 3
* or a different license than the AGPL.
*/
package org.ow2.proactive.utils;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import org.apache.log4j.Logger;
import org.objectweb.proactive.annotation.PublicAPI;
import com.google.common.base.Joiner;
/**
* Provides some methods used by the scheduler or the GUI to display some tips properly.
*
* @author The ProActive Team
* @since ProActive Scheduling 0.9
*/
@PublicAPI
public class Tools {
/**
* Format the given integer 'toFormat' to a String containing 'nbChar'
* characters
*
* @param toFormat
* the number to format
* @param nbChar
* the number of characters of the formatted result string
* @return the given integer formatted as a 'nbChar' length String.
*/
public static String formatNChar(int toFormat, int nbChar, char replacement) {
String formatted = toFormat + "";
while (formatted.length() < nbChar) {
formatted = replacement + formatted;
}
return formatted;
}
/**
* Format 2 long times into a single duration as a String. The string will
* contains the duration in Days, hours, minutes, seconds, and millis.
*
* @param start
* the first date (time)
* @param end
* the second date (time)
* @return the duration as a formatted string.
*/
public static String getFormattedDuration(long start, long end) {
if ((start < 0) || (end < 0)) {
return "Not yet";
}
long duration = Math.abs(start - end);
String formatted = "";
int tmp;
// Millisecondes
tmp = (int) duration % 1000;
duration = duration / 1000;
formatted = formatNChar(tmp, 3, ' ') + "ms" + formatted;
// Secondes
tmp = (int) duration % 60;
duration = duration / 60;
if (tmp > 0) {
formatted = formatNChar(tmp, 2, ' ') + "s " + formatted;
}
// Minutes
tmp = (int) duration % 60;
duration = duration / 60;
if (tmp > 0) {
formatted = formatNChar(tmp, 2, ' ') + "m " + formatted;
}
// Hours
tmp = (int) duration % 24;
duration = duration / 24;
if (tmp > 0) {
formatted = formatNChar(tmp, 2, ' ') + "h " + formatted;
}
// Days
tmp = (int) duration;
if (tmp > 0) {
formatted = tmp + " day" + ((tmp > 1) ? "s" : "") + " - " + formatted;
}
return formatted;
}
/**
* Return the given date as a formatted string.
*
* @param time the date as a long.
* @return the given date as a formatted string.
*/
public static String getFormattedDate(long time) {
if (time < 0) {
return "Not yet";
}
SimpleDateFormat sdf = new SimpleDateFormat();
return sdf.format(new Date(time));
}
public static String getElapsedTime(long time) {
long seconds = (System.currentTimeMillis() - time) / 1000;
long day, hou, min, sec;
StringBuilder ret = new StringBuilder();
day = seconds / (3600 * 24);
seconds -= day * (3600 * 24);
hou = seconds / 3600;
seconds -= hou * 3600;
min = seconds / 60;
sec = seconds % 60;
if (day > 0) {
ret.append(day + "d ");
ret.append(hou + "h ");
} else if (hou > 0) {
ret.append(hou + "h");
ret.append(min + "mn ");
} else if (min > 0) {
ret.append(min + "mn ");
} else {
ret.append(sec + "s ");
}
ret.append("ago");
return ret.toString();
}
/**
* Format the given string and return a long that correspond
* to the time represented by the given string.
* If the string is not proper, {@code 0} will be returned.
*
* @param pattern a time pattern that must be in [[HH:]MM:]SS
* where HH, MM, and SS are numbers
* @return a long corresponding to the given time.
*/
public static long formatDate(String pattern) {
String[] splitted = pattern.split(":");
int[] factor = new int[] { 60 * 60 * 1000, 60 * 1000, 1000 };
if (splitted.length < 0 || splitted.length > 3) {
return 0;
}
long date = 0;
try {
for (int i = splitted.length - 1; i >= 0; i--) {
date += Integer.parseInt(splitted[i]) * factor[i + 3 - splitted.length];
}
return date;
} catch (NumberFormatException e) {
return 0;
}
}
/**
* Normalize the given URL into an URL that only contains protocol://host:port/
*
* @param url the url to transform
* @return an URL that only contains protocol://host:port/
*/
public static String getHostURL(String url) {
URI uri = URI.create(url);
String scheme = (uri.getScheme() == null) ? "rmi" : uri.getScheme();
String host = (uri.getHost() == null) ? "localhost" : uri.getHost();
int port = uri.getPort();
if (port == -1) {
return scheme + "://" + host + "/";
} else {
return scheme + "://" + host + ":" + port + "/";
}
}
/**
* Parse a command line in order to split it into a string array.
* This method provides the parsing as followed :<br>
* - It is split according to the 'white space' character.<br>
* - It is possible to escape white space character using the '%' character.<br>
* - To write this '%' special char, just escape it ( '%%' ).<br>
* For example, the string "cmd arg1 arg% 2 arg%%% 3 arg4%% 5" will return the following string array :<br>
* [cmd,arg1,arg 2,arg% 3,arg4%,5]
* <p>
* This method can be mostlikely used for Runtime.exec(String[]) method.
*
* @param cmdLine The command line to parse.
* @return a string array that represents the parsed command line.
*/
public static String[] parseCommandLine(String cmdLine) {
final char specialToken = '%';
ArrayList<String> tokens = new ArrayList<>();
int i = 0;
StringBuilder tmp = new StringBuilder();
char[] cs = cmdLine.toCharArray();
while (i < cs.length) {
switch (cs[i]) {
case specialToken:
if (i + 1 < cs.length) {
tmp.append(cs[i + 1]);
i++;
}
break;
case ' ':
tokens.add(tmp.toString());
tmp = new StringBuilder();
break;
default:
tmp.append(cs[i]);
}
i++;
}
if (tmp.length() > 0) {
tokens.add(tmp.toString());
}
return tokens.toArray(new String[] {});
}
/**
* Return the extension of shell script depending the current OS
*
* @return the extension of shell script depending the current OS
*/
public static String shellExtension() {
if (System.getProperty("os.name").contains("Windows")) {
return ".bat";
} else {
return "";
}
}
/**
* Get the columned string according to the given ObjectArrayFormatter descriptor.
*
* @param oaf the ObjectArrayFormatter describing how to print the array.
* @return the columned string according the given descriptor
*/
public static String getStringAsArray(ObjectArrayFormatter oaf) {
return oaf.getAsString();
}
/**
* Translates time period string into milliseconds. Period string should
* contain symbol indication length of the period:
* <ul>
* <li>'s' - seconds
* <li>'m' - minutes
* <li>'h' - hours
* <li>'d' - days
* </ul>
*
* Examples of valid time period expressions:
* <ul>
* <li>'1m' - one minute
* <li>'1d 10h' - one day and ten hours
* </ul>
*/
public static long parsePeriod(String periodString) {
periodString = periodString.trim();
if (periodString.isEmpty()) {
throw new IllegalArgumentException("Period string is empty");
}
long total = 0;
StringBuilder numberStr = new StringBuilder();
for (int i = 0; i < periodString.length(); i++) {
char ch = periodString.charAt(i);
if (Character.isSpaceChar(ch)) {
continue;
} else if (Character.isDigit(ch)) {
numberStr.append(ch);
} else {
long millis;
if (ch == 's') {
millis = 1000;
} else if (ch == 'm') {
millis = 1000 * 60;
} else if (ch == 'h') {
millis = 1000 * 60 * 60;
} else if (ch == 'd') {
millis = 1000 * 60 * 60 * 24;
} else {
throw new IllegalArgumentException("Invalid period string: " + ch);
}
if (numberStr.length() == 0) {
throw new IllegalArgumentException("Period length isn't specified");
}
total += Long.valueOf(numberStr.toString()) * millis;
numberStr = new StringBuilder();
}
}
if (numberStr.length() != 0) {
throw new IllegalArgumentException("Period string isn't specified");
}
return total;
}
/**
* Log available script engines at INFO level.
*
* @param logger the logger instance used to log available script engines.
*/
public static void logAvailableScriptEngines(Logger logger) {
if (!logger.isInfoEnabled()) {
return;
}
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
List<ScriptEngineFactory> engineFactories = scriptEngineManager.getEngineFactories();
StringBuilder buffer = new StringBuilder();
buffer.append("Available script engines: ");
int engineFactoriesCount = engineFactories.size();
for (int i = 0; i < engineFactoriesCount; i++) {
ScriptEngineFactory scriptEngineFactory = engineFactories.get(i);
buffer.append(scriptEngineFactory.getEngineName());
buffer.append(" (");
buffer.append(scriptEngineFactory.getEngineVersion());
buffer.append(")");
if (i < engineFactoriesCount - 1) {
buffer.append(", ");
}
}
logger.info(buffer.toString());
}
}