/**
* Copyright 2016 Nabarun Mondal
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.noga.njexl.lang.extension;
import com.noga.njexl.lang.*;
import com.noga.njexl.lang.extension.dataaccess.DBManager;
import com.noga.njexl.lang.extension.dataaccess.DataMatrix;
import com.noga.njexl.lang.extension.dataaccess.EnumWrapper;
import com.noga.njexl.lang.extension.dataaccess.XmlMap;
import com.noga.njexl.lang.extension.datastructures.Heap;
import com.noga.njexl.lang.extension.datastructures.ListSet;
import com.noga.njexl.lang.extension.datastructures.Tuple;
import com.noga.njexl.lang.extension.datastructures.XList;
import com.noga.njexl.lang.extension.iterators.*;
import com.noga.njexl.lang.extension.oop.ScriptClassInstance;
import com.noga.njexl.lang.internal.Introspector;
import com.noga.njexl.lang.parser.*;
import jdk.nashorn.internal.runtime.regexp.joni.Regex;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Duration;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import java.io.*;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.noga.njexl.lang.Interpreter.AnonymousParam;
import static com.noga.njexl.lang.Interpreter.NULL;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* <pre>
* This is the extension which would ensure
* it is a proper language.
* </pre>
*/
public final class TypeUtility {
public static final String TYPE = "type";
public static Introspector introspector;
/**
* ***** The Casting Calls ******
*/
public static final String ENUM = "enum";
public static final String INT = "int";
public static final String CHAR = "char";
public static final String SHORT = "short";
public static final String BYTE = "byte";
public static final String DOUBLE = "double";
public static final String FLOAT = "float";
public static final String LONG = "long";
public static final String TIME = "time";
public static final String DATE = "date";
public static final String INSTANT = "instant";
public static final String STRING = "str";
public static final String BOOL = "bool";
public static final String BIGINT = "INT";
public static final String BIGDECIMAL = "DEC";
public static final String NUMBER = "NUM";
public static final String COUNTABLE = "Z";
public static final String RATIONAL = "Q";
public static final String LOAD_PATH = "load";
public static final String BYE = "bye";
public static final String ASSERT = "assert";
public static final String TEST = "test";
public static final String ERROR = "error";
/**
* ******* The Utility Calls *********
*/
public static final String LIST = "list";
public static final String FILTER = "filter";
public static final String SELECT = "select";
public static final String PARTITION = "partition";
public static final String FIND = "find";
public static final String INDEX = "index";
public static final String RINDEX = "rindex";
public static final String JOIN = "join";
public static final String PROJECT = "project";
public static final String SUBLIST = "sub";
public static final String LITERAL_LIST = "LIST";
public static final String ARRAY = "array";
public static final String ARRAY_FROM_LIST = "arrayFromList";
public static final String SET = "set";
public static final String MULTI_SET1 = "multiset";
public static final String MULTI_SET2 = "mset";
public static final String MULTI_SET3 = "setm";
public static final String HEAP = "heap";
public static final String DICTIONARY = "dict";
public static final String RANGE = "range";
public static final String MINMAX = "minmax";
public static final String SQLMATH = "sqlmath";
public static final String SORT_ASCENDING = "sorta";
public static final String SORT_DESCENDING = "sortd";
public static final String RANDOM = "random";
public static final String SHUFFLE = "shuffle";
public static final String LEFT_FOLD = "lfold";
public static final String RIGHT_FOLD = "rfold";
public static final String TRY = "try";
public static final String SYSTEM = "system";
public static final String THREAD = "thread";
public static final String POLL = "until";
/**
* IO calls
*/
public static final String READ = "read";
public static final String READ_LINES = "lines";
public static final String WRITE = "write";
public static final String PRINT = "print";
public static final String SEND = "send";
public static final String FOPEN = "fopen";
public static final String JSON = "json";
public static final String XML = "xml";
public static final String TOKEN = "tokens";
public static final String HASH = "hash";
public static final String MATRIX = "matrix";
public static final String DATABASE = "db";
public static final String INSPECT = "inspect";
public static final String ATOMIC = "atomic";
/**
* <pre>
* Take a look around here.
* http://stackoverflow.com/questions/5606338/cast-primitive-type-array-into-object-array-in-java
* </pre>
*/
public static final Class<?>[] ARRAY_PRIMITIVE_TYPES = {
int[].class, float[].class, double[].class, boolean[].class,
byte[].class, short[].class, long[].class, char[].class};
public static Object dataBase(Object... args) throws Exception {
if (args.length == 0) return new DBManager();
String loc = String.valueOf(args[0]);
return new DBManager(loc);
}
public static Number Z(Object...args){
Object n = castBigInteger(args);
if ( n == null ) return null;
String s = String.valueOf(n);
ASTNumberLiteral numberLiteral = new ASTNumberLiteral(Parser.JJTNUMBERLITERAL);
numberLiteral.setNatural(s);
return numberLiteral.getLiteral();
}
public static Number Q(Object...args){
Object d = castBigDecimal(args);
if ( d == null ) return null;
String s = String.valueOf(d);
ASTNumberLiteral numberLiteral = new ASTNumberLiteral(Parser.JJTNUMBERLITERAL);
numberLiteral.setReal(s);
return numberLiteral.getLiteral();
}
public static Number NUM(Object...args){
Number z = Z(args);
Number q = Q(args);
if ( q instanceof BigDecimal ){
try{
((BigDecimal) q).toBigIntegerExact();
return z;
}catch (ArithmeticException ae){
return q;
}
}
if ( q.doubleValue() == z.doubleValue() ){
return z;
}
return q;
}
public static Object atomic(Object... args) throws Exception {
if (args.length == 0) return null;
if (args[0] instanceof Boolean) {
return new AtomicBoolean((Boolean) args[0]);
}
if (args[0] instanceof Integer) {
return new AtomicInteger((Integer) args[0]);
}
if (args[0] instanceof Long) {
return new AtomicLong((Long) args[0]);
}
if (args[0] instanceof Map) {
return Collections.synchronizedMap((Map) args[0]);
}
if (args[0] instanceof List) {
return Collections.synchronizedList((List) args[0]);
}
if (args[0] instanceof Set) {
return Collections.synchronizedSet((Set) args[0]);
}
if (args[0] instanceof Collection) {
return Collections.synchronizedCollection((Collection) args[0]);
}
if (args[0] != null) {
if (args.getClass().isArray()) {
return new Tuple(args[0]);
}
return new AtomicReference<>(args[0]);
}
return null;
}
public static Object inspect(Object... args) throws Exception {
if (args.length == 0) return introspector;
if (args[0] == null) return introspector;
Class z;
if (args[0] instanceof Class) {
z = (Class) args[0];
} else {
z = args[0].getClass();
}
Map map = new HashMap<>();
map.put("t", z.getName());
List fi = new XList<>();
List fs = new XList<>();
String[] fields = introspector.getFieldNames(z);
for (String f : fields) {
Field field = introspector.getField(z, f);
XList.Pair pair = new XList.Pair(f, field.getType());
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
fs.add(pair);
} else {
fi.add(pair);
}
}
List ml = new XList<>();
String[] methods = introspector.getMethodNames(z);
for (String m : methods) {
ml.add(m);
}
map.put("F", Collections.unmodifiableList(fs));
map.put("f", Collections.unmodifiableList(fi));
map.put("m", Collections.unmodifiableList(ml));
return Collections.unmodifiableMap(map);
}
public static Object matrix(Object... args) throws Exception {
if (args.length == 0) return null;
String loc = String.valueOf(args[0]);
args = shiftArrayLeft(args, 1);
return DataMatrix.loc2matrix(loc, args);
}
/**
* Opens a file for read/write
*
* @param args arguments, 2nd one is the mode "r/w/a"
* @return PrintStream or BufferedReader
* @throws Exception in case of any error
*/
public static Object fopen(Object... args) throws Exception {
if (args.length == 0) {
return new BufferedReader(new InputStreamReader(System.in));
}
String file = String.valueOf(args[0]);
if (args.length == 1) {
return new BufferedReader(
new InputStreamReader(new FileInputStream(file)));
}
String mode = String.valueOf(args[1]);
if ("r".equalsIgnoreCase(mode)) {
if ("@IN".equalsIgnoreCase(file)) {
return new BufferedReader(new InputStreamReader(System.in));
}
return new BufferedReader(
new InputStreamReader(new FileInputStream(file)));
}
if ("w".equalsIgnoreCase(mode)) {
if ("@OUT".equalsIgnoreCase(file)) return System.out;
if ("@ERR".equalsIgnoreCase(file)) return System.err;
return new PrintStream(file);
}
if ("a".equalsIgnoreCase(mode)) {
return new PrintStream(new FileOutputStream(file, true));
}
return System.err;
}
/**
* Tokenizes a string
*
* @param args first is the string, next the regex, then true|false for the case matching
* @return a matcher if there is no anonymous arg, else a list of result of all matches
*/
public static Object tokenize(Object... args) {
if (args.length == 0) return false;
AnonymousParam anon = null;
if (args[0] instanceof AnonymousParam) {
anon = (AnonymousParam) args[0];
args = shiftArrayLeft(args, 1);
}
int flags = Pattern.DOTALL | Pattern.MULTILINE;
// in case a string is given, use this as regex and return a pattern
if (args.length < 2) return Pattern.compile(String.valueOf(args[0]), flags);
String text = String.valueOf(args[0]) ;
String regex = String.valueOf(args[1]);
if (args.length > 2) {
if (castBoolean(args[2])) {
flags |= Pattern.CASE_INSENSITIVE;
}
}
Pattern pattern = Pattern.compile(regex, flags);
Matcher matcher = pattern.matcher(text);
if (anon == null) return matcher;
List l = new XList<>();
// else ?
int i = -1;
while (matcher.find()) {
anon.setIterationContextWithPartial(text, matcher.group(), ++i, l);
Object o;
try {
o = anon.execute();
if (o instanceof JexlException.Continue) {
if (((JexlException.Continue) o).hasValue) {
l.add(((JexlException.Continue) o).value);
}
continue;
}
if (o instanceof JexlException.Break) {
if (((JexlException.Break) o).hasValue) {
l.add(((JexlException.Break) o).value);
}
break;
}
} catch (Exception e) {
o = null;
}
l.add(o);
}
return l;
}
/**
* Folds as in functional programming
* https://en.wikipedia.org/wiki/Fold_(higher-order_function)
*
* @param right : if true, does a right fold
* @param args the arguments to the fold
* @return the result of the fold
*/
public static Object fold(boolean right, Object... args) {
if (args.length == 0) return null;
AnonymousParam anon = null;
if (args[0] instanceof AnonymousParam) {
anon = (AnonymousParam) args[0];
args = shiftArrayLeft(args, 1);
}
if (args.length == 0) return null;
Object partial = null;
if (args.length > 1) {
partial = args[1];
}
if (args[0] instanceof YieldedIterator) {
// this is a separate branch of stuff
YieldedIterator itr = (YieldedIterator) args[0];
if (right) {
// switch it...
itr = itr.inverse();
}
if (anon == null) {
return castString(itr.list());
}
int i = -1;
while (itr.hasNext()) {
i++;
Object o = itr.next();
anon.setIterationContextWithPartial(itr, o, i, partial);
try {
Object r = anon.execute();
if (r instanceof JexlException.Continue) {
if (((JexlException.Continue) r).hasValue) {
partial = ((JexlException.Continue) r).value;
}
continue;
}
if (r instanceof JexlException.Break) {
if (((JexlException.Break) r).hasValue) {
partial = ((JexlException.Break) r).value;
}
break;
}
partial = r;
} catch (Throwable e) {
// log?
throw e;
}
}
return partial;
}
List l = combine(args[0]);
int size = l.size();
if (anon == null) {
if (size == 0) return "";
String sep = SetOperations.SEP;
if (args.length > 1) {
sep = String.valueOf(args[1]);
}
if (right) {
StringBuffer sb = new StringBuffer();
sb.append(l.get(size - 1));
for (int i = 1; i < size; i++) {
sb.append(sep);
sb.append(l.get(size - i - 1));
}
return sb.toString();
}
return castString(l, sep);
}
for (int i = 0; i < size; i++) {
int j = right ? (size - i - 1) : i;
Object o = l.get(j);
anon.setIterationContextWithPartial(l, o, i, partial);
try {
Object r = anon.execute();
if (r instanceof JexlException.Continue) {
if (((JexlException.Continue) r).hasValue) {
partial = ((JexlException.Continue) r).value;
}
continue;
}
if (r instanceof JexlException.Break) {
if (((JexlException.Break) r).hasValue) {
partial = ((JexlException.Break) r).value;
}
break;
}
partial = r;
} catch (Throwable e) {
//log?
throw e;
}
}
return partial;
}
/**
* http://en.wikipedia.org/wiki/Fisher–Yates_shuffle#The_modern_algorithm
*
* @param args the argument
* @return true if did shuffle, false if could not
*/
public static boolean shuffle(Object... args) {
if (args.length == 0) return false;
if (args[0] == null) return false;
SecureRandom random = new SecureRandom();
if (args[0] instanceof List) {
List l = (List) args[0];
int size = l.size();
for (int i = size - 1; i >= 0; i--) {
int j = random.nextInt(i + 1);
Object tmp = l.get(j);
l.set(j, l.get(i));
l.set(i, tmp);
}
}
if (args[0].getClass().isArray()) {
//different treatment
int size = Array.getLength(args[0]);
for (int i = size - 1; i >= 0; i--) {
int j = random.nextInt(i + 1);
Object tmp = Array.get(args[0], j);
Array.set(args[0], j, Array.get(args[0], i));
Array.set(args[0], i, tmp);
}
}
return true;
}
public static final SecureRandom random = new SecureRandom();
/**
* Generates some random stuff
* If args length is empty or args[0] null returns a SecureRandom object
* For a list, string, iterator, selects a random element from it and returns that
* If input type is float, double, long it returns the nextType()
* If input is precisely 0, or 0,0 it returns nextGaussian
* If input it integer and non zero, that is random(x) and random(x,y)
* Then returns nextInt(x) and ranges it off
*
* @param args arguments
* @return see the doc
*/
public static Object random(Object... args) {
if (args.length == 0) return random;
if (args[0] == null) return random;
if (args[0] instanceof YieldedIterator) {
args[0] = ((YieldedIterator) args[0]).list();
} else if (args[0] instanceof Iterator) {
args[0] = YieldedIterator.list((Iterator) args[0]);
}
if (args[0] instanceof Boolean) {
return random.nextBoolean();
}
if (args[0] instanceof Number) {
if (args[0] instanceof Long) {
return random.nextLong();
}
if (args[0] instanceof Double) {
return random.nextDouble();
}
if (args[0] instanceof Float) {
return random.nextFloat();
}
if (args[0] instanceof BigInteger) {
int size = ((BigInteger) args[0]).toString(2).length();
StringBuffer buf = new StringBuffer();
if (random.nextBoolean()) {
buf.append("-");
}
for (int i = 0; i < size; i++) {
long l = Math.abs(random.nextLong());
buf.append(l);
}
return new BigInteger(buf.toString());
}
if (args[0] instanceof BigDecimal) {
int size = ((BigDecimal) args[0]).precision() + 1;
StringBuffer buf = new StringBuffer();
if (random.nextBoolean()) {
buf.append("-");
}
buf.append("0.");
for (int i = 0; i < size; i++) {
long l = Math.abs(random.nextLong());
buf.append(l);
}
return new BigDecimal(buf.toString());
}
int x = 0;
int y = ((Number) args[0]).intValue();
if (args.length > 1) {
x = y;
y = ((Number) args[1]).intValue();
}
int min = Math.min(x, y);
int max = Math.max(x, y);
if (max == 0) {
return random.nextGaussian();
}
return (min + random.nextInt(max - min));
}
if (args[0] instanceof String) {
String l = (String) args[0];
int index = random.nextInt(l.length());
if (args.length > 1) {
// how many stuff we need?
int count = castInteger(args[1], 1);
StringBuffer buf = new StringBuffer();
while (count-- > 0) {
char c = l.charAt(index);
buf.append(c);
index = random.nextInt(l.length());
}
return buf.toString();
}
return l.charAt(index);
}
if (args[0] instanceof List) {
List l = (List) args[0];
int index = random.nextInt(l.size());
if (args.length > 1) {
// how many stuff we need?
int count = castInteger(args[1], 1);
List r = new ArrayList<>();
while (count-- > 0) {
Object o = l.get(index);
r.add(o);
index = random.nextInt(l.size());
}
return r;
}
return l.get(index);
}
if (args[0].getClass().isArray()) {
int size = Array.getLength(args[0]);
int index = random.nextInt(size);
if (args.length > 1) {
// how many stuff we need?
int count = castInteger(args[1], 1);
List r = new ArrayList<>();
while (count-- > 0) {
Object o = Array.get(args[0], index);
r.add(o);
index = random.nextInt(size);
}
return r;
}
return Array.get(args[0], index);
}
if (args[0] instanceof Class && ((Class) args[0]).isEnum()) {
Object[] values = ((Class) args[0]).getEnumConstants();
int index = random.nextInt(values.length);
if (args.length > 1) {
// how many stuff we need?
int count = castInteger(args[1], 1);
List r = new ArrayList<>();
while (count-- > 0) {
Object o = values[index];
r.add(o);
index = random.nextInt(values.length);
}
return r;
}
return values[index];
}
if (args[0] instanceof Map) {
Map m = (Map) args[0];
List l = new ListSet<>(m.keySet());
int index = random.nextInt(l.size());
if (args.length > 1) {
// how many stuff we need?
int count = castInteger(args[1], 1);
Map r = new HashMap<>();
while (count-- > 0) {
Object k = l.get(index);
r.put(k, m.get(k));
index = random.nextInt(l.size());
}
return r;
}
// return the tuple
return new XList.Pair(l.get(index), m.get(l.get(index)));
}
return random;
}
public static Object type(Object... args) {
if (args.length == 0) {
return null;
}
if (args[0] == null) {
return null;
}
if (args[0] instanceof ScriptClassInstance) {
return ((ScriptClassInstance) args[0]).getNClass();
}
return args[0].getClass();
}
public static final String HASH_MD5 = "MD5";
public static String hash(Object... args) {
if (args.length == 0) return "";
String algorithm = HASH_MD5;
String text = String.valueOf(args[0]);
if (args.length > 1) {
algorithm = text;
text = String.valueOf(args[1]);
}
if ("e64".equalsIgnoreCase(algorithm)) {
// do base 64 encoding
return Base64.getEncoder().encodeToString(text.getBytes(StandardCharsets.UTF_8));
}
if ("d64".equalsIgnoreCase(algorithm)) {
// do base 64 decoding
byte[] barr = Base64.getDecoder().decode(text.getBytes(StandardCharsets.UTF_8));
return new String(barr);
}
try {
MessageDigest m = MessageDigest.getInstance(algorithm);
m.update(text.getBytes(), 0, text.length());
BigInteger bi = new BigInteger(1, m.digest());
return bi.toString(16);
} catch (Exception e) {
}
return new Integer(text.hashCode()).toString();
}
public static Object json(Object... args) throws Exception {
if (args.length == 0) {
return null;
}
String text = "";
if (args.length > 1) {
String directive = args[0].toString().toLowerCase();
text = args[1].toString();
if (directive.startsWith("f")) {
// file
File file = new File(text);
if (file.exists()) {
// this is the file name
text = readToEnd(text);
} else {
return null;
}
}
} else {
// auto resolve mode...
text = args[0].toString();
File file = new File(text);
if (file.exists()) {
// this is the file name
text = readToEnd(text);
}
}
text = text.replaceAll("[\\r\\n]", " ");
// this is for the empty dict issue : {:}
text = text.replaceAll("\\{[ \t\n\r]*\\}", "\\{:\\}");
JexlEngine jexlEngine = new JexlEngine();
Script sc = jexlEngine.createScript(text);
JexlContext context = new MapContext();
return sc.execute(context);
}
public static Object xml(Object... args) throws Exception {
if (args.length == 0) {
return null;
}
if (args[0] instanceof Node) {
Node n = (Node) args[0];
XmlMap.XmlElement e = new XmlMap.XmlElement(n, null);
return e;
}
if (args[0] instanceof NodeList) {
NodeList nL = (NodeList) args[0];
ArrayList list = new ArrayList();
for (int i = 0; i < nL.getLength(); i++) {
Node n = nL.item(i);
XmlMap.XmlElement e = new XmlMap.XmlElement(n, null);
list.add(e);
}
return list;
}
if ( !( args[0] instanceof String ) ){
return XmlMap.xml(args[0]);
}
// fall back on string now ...
String text = args[0].toString();
File file = new File(text);
String encoding = "UTF-8" ;
if ( args.length > 1 ){
encoding = String.valueOf(args[1]);
}
if (file.exists()) {
// this is the file name
return XmlMap.file2xml(file.getAbsolutePath(), encoding );
}
return XmlMap.string2xml(text, encoding);
}
public static String readStream(InputStream inputStream) throws Exception {
StringBuffer buf = new StringBuffer();
BufferedReader in = new BufferedReader(
new InputStreamReader(inputStream));
String inputLine;
while ((inputLine = in.readLine()) != null) {
buf.append(inputLine);
buf.append("\n");
}
in.close();
return buf.toString();
}
public static String readUrl(URL url, Object... args) throws Exception {
// set reasonable timeout
int conTimeOut = 10000;
// set reasonable read timeout
int readTimeOut = 10000;
if (args.length > 0) {
conTimeOut = castInteger(args[0], conTimeOut);
if (args.length > 1) {
readTimeOut = castInteger(args[1], readTimeOut);
}
}
URLConnection conn = url.openConnection();
conn.setConnectTimeout(conTimeOut);
conn.setReadTimeout(readTimeOut);
return readStream(conn.getInputStream());
}
public static String readToEnd(String location, Object... args) throws Exception {
// if the fileName is URL?
String name = location.toLowerCase();
if (name.startsWith("http://") ||
name.startsWith("https://") ||
name.startsWith("ftp://")) {
URL url = new URL(location);
return readUrl(url, args);
}
List<String> lines = Files.readAllLines(new File(location).toPath());
StringBuffer buffer = new StringBuffer();
for (String l : lines) {
buffer = buffer.append(l).append("\n");
}
return buffer.toString();
}
public static final Pattern URL =
Pattern.compile("^http(s)?://.+", Pattern.CASE_INSENSITIVE);
public static String send(Object... args) throws Exception {
if (args.length == 0) return "";
String u = String.valueOf(args[0]);
String method = "GET";
Object params = Collections.EMPTY_MAP;
Map headers = Collections.EMPTY_MAP;
int connectionTimeOut = 0;
int readTimeOut = 0;
if (args.length > 1) {
method = String.valueOf(args[1]);
if (args.length > 2) {
params = args[2];
if (args.length > 3) {
headers = (Map) args[3];
if (args.length > 4) {
connectionTimeOut = castInteger(args[4], 0);
if (args.length > 5) {
readTimeOut = castInteger(args[5], 0);
}
}
}
}
}
return sendUrl(u, method, params, headers, connectionTimeOut, readTimeOut);
}
public static String sendUrl(String u, String method,
Object body,
Map<String, String> headers,
int connectionTimeOut, int readTimeOut)
throws Exception {
boolean get = false;
if ("GET".equalsIgnoreCase(method)) {
get = true;
}
Map<String, String> params;
String urlParameters;
StringBuffer buf;
if (body instanceof Map) {
params = (Map) body;
buf = new StringBuffer();
Iterator<String> iterator = params.keySet().iterator();
if (iterator.hasNext()) {
String k = iterator.next();
String v = params.get(k);
buf.append(k).append("=").append(v);
while (iterator.hasNext()) {
buf.append("&");
k = iterator.next();
v = params.get(k);
buf.append(k).append("=").append(v);
}
}
urlParameters = buf.toString();
} else {
urlParameters = String.valueOf(body);
}
if (get) {
URL url = new URL(u + "?" + urlParameters);
return readUrl(url);
}
URL url = new URL(u);
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
((HttpURLConnection) conn).setRequestMethod(method);
String type = "application/x-www-form-urlencoded";
conn.setRequestProperty("Content-Type", type);
for (String key : headers.keySet()) {
conn.setRequestProperty(key, headers.get(key));
}
conn.setRequestProperty("Content-Length", String.valueOf(urlParameters.length()));
conn.setConnectTimeout(connectionTimeOut);
conn.setReadTimeout(readTimeOut);
OutputStream writer = conn.getOutputStream();
writer.write(urlParameters.getBytes());
writer.flush();
String line;
BufferedReader reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
buf = new StringBuffer();
while ((line = reader.readLine()) != null) {
buf.append(line).append("\n");
}
reader.close();
writer.close();
return buf.toString();
}
public static Object writeFile(Object... args) throws Exception {
if (args.length == 0) {
System.out.println();
return NULL;
}
String path = String.valueOf(args[0]);
if (URL.matcher(path).matches()) {
args = shiftArrayLeft(args, 1);
return send(path, "POST", makeDict(args));
}
PrintStream ps = System.out;
if (args[0] instanceof PrintStream) {
ps = (PrintStream) args[0];
args = shiftArrayLeft(args, 1);
}
if (args.length == 0) {
ps.println();
return NULL;
}
if (args.length == 1) {
ps.printf("%s\n", args[0]);
return NULL;
}
String fmt = String.valueOf(args[0]);
args = shiftArrayLeft(args, 1);
if (fmt.contains("%")) {
// formats...
ps.printf(fmt, args);
return NULL;
}
String fileName = fmt;
String data = "42";
if (args.length > 0) {
data = String.valueOf(args[0]);
}
Files.write(new File(fileName).toPath(), data.getBytes());
return NULL;
}
public static String read(Object... args) throws Exception {
if (args.length == 0) {
return System.console().readLine();
}
if (args[0] instanceof InputStream) {
return readStream((InputStream) args[0]);
}
if (args[0] instanceof String) {
String loc = (String) args[0];
args = shiftArrayLeft(args, 1);
return readToEnd(loc, args);
}
if (args[0] instanceof URL) {
URL loc = (URL) args[0];
args = shiftArrayLeft(args, 1);
return readUrl(loc, args);
}
if (args[0] instanceof Path) {
return readToEnd(((Path) args[0]).toFile().getCanonicalPath());
}
return null;
}
public static Object readLines(Object... args) throws Exception {
XList<String> lines = null;
if (args.length == 0) {
lines = new XList<>();
while (true) {
String l = System.console().readLine();
if (l == null) {
break;
}
lines.add(l);
}
return lines;
}
if (args.length != 1) {
lines = new XList<>(Files.readAllLines(new File(args[0].toString()).toPath()));
return lines;
}
return new FileIterator(String.valueOf(args[0]));
}
public static BigInteger castBigInteger(Object... args) {
if (args.length == 0) {
return BigInteger.ZERO;
}
if ( args[0] instanceof BigInteger ){ return (BigInteger)args[0]; }
if ( JexlArithmetic.isTimeLike(args[0]) ){ return BigInteger.valueOf( castLong( args[0])); }
int base = 10;
BigInteger fallBack = null;
if (args.length > 1) {
base = castInteger(args[1]);
if (args.length > 2) {
fallBack = castBigInteger(args[2]);
}
}
String val = String.valueOf(args[0]).trim();
try {
return new BigInteger(val, base);
} catch (Throwable t) {
try {
BigDecimal d = new BigDecimal(val);
return d.toBigInteger();
}catch (Throwable t2){
// nothing...
}
return fallBack;
}
}
public static BigDecimal castBigDecimal(Object... args) {
if (args.length == 0) {
return BigDecimal.ZERO;
}
if ( args[0] instanceof BigDecimal ){ return (BigDecimal) args[0]; }
if ( args[0] instanceof BigInteger ){ return new BigDecimal( (BigInteger) args[0] ); }
BigDecimal fallBack = null;
if (args.length > 1) {
fallBack = castBigDecimal(args[1]);
}
String val = String.valueOf(args[0]).trim();
try {
return new BigDecimal(val, MathContext.UNLIMITED);
} catch (Throwable t) {
return fallBack;
}
}
public static Double castDouble(Object... args) {
if (args.length == 0) {
return 0.0;
}
try {
if (args[0] instanceof Double) {
return (Double) args[0];
}
if (args[0] instanceof Float) {
return ((Float) args[0]).doubleValue();
}
Object objectValue = args[0];
Double val = Double.valueOf(objectValue.toString().trim());
return val;
} catch (Exception e) {
if (args.length > 1) {
return castDouble(args[1]);
}
return null;
}
}
public static Float castFloat(Object... args) {
Double doubleValue = castDouble(args);
if (doubleValue != null) {
return Float.valueOf(doubleValue.floatValue());
}
return null;
}
public static Byte castByte(Object... args) {
Integer i = castInteger(args);
if (i != null) {
return new Byte(i.byteValue());
}
Character c = castChar(args);
if (c != null) {
new Byte(new Integer(c).byteValue());
}
return null;
}
public static Character castChar(Object... args) {
if (args.length == 0) {
return 0;
}
if (args[0] instanceof Character) {
return (Character) args[0];
}
if (args[0] instanceof String) {
String s = ((String) args[0]);
if (s.length() != 1) {
return null;
}
return s.charAt(0);
}
Double doubleValue = castDouble(args);
if (doubleValue != null) {
char[] cc = Character.toChars(doubleValue.intValue());
return new Character(cc[0]);
}
return null;
}
public static Short castShort(Object... args) {
Integer i = castInteger(args);
if (i != null) {
return new Short(i.shortValue());
}
Character c = castChar(args);
if (c != null) {
return new Short(new Integer(c).shortValue());
}
return null;
}
public static Integer castInteger(Object... args) {
Double doubleValue = castDouble(args);
if (doubleValue != null) {
return Integer.valueOf(doubleValue.intValue());
}
return null;
}
public static Long castLong(Object... args) {
if ( args.length > 0 && JexlArithmetic.isTimeLike(args[0])){
if ( args[0] instanceof Date ){
return ((Date)args[0]).getTime();
}
if ( args[0] instanceof DateTime ){
return ((DateTime)args[0]).toDate().getTime();
}
if ( args[0] instanceof Instant ){
return ((Instant)args[0]).toEpochMilli();
}
}
Double doubleValue = castDouble(args);
if (doubleValue != null) {
return Long.valueOf(doubleValue.longValue());
}
return null;
}
public static DateTime castTime(Object... args) {
DateTime dt = null;
if (args.length == 0) {
return new DateTime();
}
if (args[0] instanceof Date || args[0] instanceof DateTime) {
dt = new DateTime(args[0]);
} else if (args[0] instanceof Instant) {
dt = new DateTime(Date.from((Instant) args[0]));
}
if (args[0] instanceof Number) {
dt = new DateTime(((Number) args[0]).longValue());
}
if (dt != null) {
if (args.length > 1) {
DateTimeZone zone = DateTimeZone.forID(String.valueOf(args[1]));
return dt.withZone(zone);
}
return dt;
}
DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("yyyyMMdd");
try {
if (args.length > 1) {
dateTimeFormatter = DateTimeFormat.forPattern(args[1].toString());
}
dt = DateTime.parse(args[0].toString(), dateTimeFormatter);
if (args.length > 2) {
DateTimeZone zone = DateTimeZone.forID(String.valueOf(args[2]));
return dt.withZone(zone);
}
return dt;
} catch (Exception e) {
}
return null;
}
public static Instant castInstant(Object... args) {
DateTime dt = castTime(args);
return dt.toDate().toInstant();
}
public static Date castDate(Object... args) {
if (args.length == 0) {
return new Date();
}
if (args[0] instanceof Date) {
return (Date) args[0];
}
if (args[0] instanceof DateTime) {
return ((DateTime) args[0]).toDate();
}
if (args[0] instanceof Instant) {
return Date.from(((Instant) args[0]));
}
if (args[0] instanceof Number) {
return new Date(((Number) args[0]).longValue());
}
SimpleDateFormat dateTimeFormatter = new SimpleDateFormat("yyyyMMdd");
try {
dateTimeFormatter.setLenient(false);
if (args.length > 1) {
dateTimeFormatter = new SimpleDateFormat(args[1].toString());
if (args.length > 2) {
dateTimeFormatter.setLenient(castBoolean(args[2], false));
if (args.length > 3) {
dateTimeFormatter.setTimeZone(TimeZone.getTimeZone(args[3].toString()));
}
}
}
return dateTimeFormatter.parse(args[0].toString());
} catch (Exception e) {
}
return null;
}
public static Boolean castBoolean(Object... args) {
if (args.length == 0) {
return Boolean.FALSE;
}
if (args[0] instanceof Boolean) {
return (Boolean) args[0];
}
if (args[0] instanceof String) {
String litValue = (String) args[0];
litValue = litValue.toLowerCase();
if (litValue.equals("true")) {
return Boolean.TRUE;
}
if (litValue.equals("false")) {
return Boolean.FALSE;
}
}
Double d = castDouble(args);
if (d != null) {
return new Boolean(d != 0);
}
if (args.length > 1) {
List opts = from(args[1]);
if (opts.size() > 1) {
// options are passed to match
Object t = opts.get(0);
Object f = opts.get(1);
if (Objects.equals(args[0], t)) return true;
if (Objects.equals(args[0], f)) return false;
}
return castBoolean(args[1]);
}
return null;
}
public static String castString(Object... args) {
if (args.length == 0) {
return "";
}
if (args[0] == null) {
/* what should I return?
Theoretically null, "" , "null" are possible.
But then, I choose 'null'.
*/
return "null"; // because it is nJexl null param
}
if (args[0] instanceof AnonymousParam) {
if (args.length > 1) {
if (args[1] instanceof Collection || args[1].getClass().isArray()) {
Object[] _args = new Object[]{args[0], args[1]};
String sep = SetOperations.SEP;
if (args.length > 2) {
sep = String.valueOf(args[2]);
}
List l = combine(_args);
return castString(l, sep);
}
}
AnonymousParam anon = (AnonymousParam) args[0];
args = shiftArrayLeft(args, 1);
if (args.length > 0) {
anon.setIterationContext(args[0], args[0], -1);
Object ret = anon.execute();
args[0] = ret; //set it up
return castString(args);
}
return "";
}
if (args[0] instanceof String) {
return (String) args[0];
}
if (args[0] instanceof DateTime) {
DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("yyyyMMdd");
if (args.length > 1 && args[1] != null) {
dateTimeFormatter = DateTimeFormat.forPattern(args[1].toString());
}
try {
return dateTimeFormatter.print((DateTime) args[0]);
} catch (Exception e) {
return args[0].toString(); // make it return faster...
}
}
if (args[0] instanceof Date) {
SimpleDateFormat dateTimeFormatter = new SimpleDateFormat("yyyyMMdd");
if (args.length > 1 && args[1] != null) {
dateTimeFormatter = new SimpleDateFormat(args[1].toString());
}
try {
return dateTimeFormatter.format(args[0]);
} catch (Exception e) {
return args[0].toString();
}
}
if (args[0] instanceof Float ||
args[0] instanceof Double ||
args[0] instanceof BigDecimal) {
if (args.length > 1) {
if (args[1] instanceof Integer) {
String fmt = String.format("%%.%df", args[1]);
return String.format(fmt, args[0]);
}
if (args[1] instanceof String) {
DecimalFormat format = new DecimalFormat(args[1].toString());
return format.format(args[0]);
}
}
return args[0].toString();
}
Class c = args[0].getClass();
if (List.class.isAssignableFrom(c) || c.isArray()) {
List l = from(args[0]);
if (l.isEmpty()) return "";
StringBuffer buf = new StringBuffer();
String sep = ",";
if (args.length > 1 && args[1] != null) {
sep = args[1].toString();
}
Iterator itr = l.iterator();
Object o = itr.next();
buf.append(o);
while (itr.hasNext()) {
o = itr.next();
buf.append(sep).append(o);
}
String ret = buf.toString();
return ret;
}
if (args.length > 1 && args[1] instanceof Number && args[0] instanceof Number) {
int base = ((Number) args[1]).intValue();
if (args[0] instanceof BigInteger) {
return ((BigInteger) args[0]).toString(base);
}
long l = ((Number) args[0]).longValue();
return BigInteger.valueOf(l).toString(base);
}
return XmlMap.toJSON(args[0]);
}
public static XList makeLiteralList(Object... argv) {
XList list = new XList();
for (int i = 0; i < argv.length; i++) {
list.add(argv[i]);
}
return list;
}
public static Object[] getArray(Object val) {
Class<?> valKlass = val.getClass();
Object[] outputArray = null;
for (Class<?> arrKlass : ARRAY_PRIMITIVE_TYPES) {
if (valKlass.isAssignableFrom(arrKlass)) {
int arrlength = Array.getLength(val);
outputArray = new Object[arrlength];
for (int i = 0; i < arrlength; ++i) {
outputArray[i] = Array.get(val, i);
}
break;
}
}
if (outputArray == null) // not primitive type array
outputArray = (Object[]) val;
return outputArray;
}
/**
* <pre>
* I am given an element, I want to make a mutable list out of it.
* If This is actually a list, then creates a list exactly the same, only mutable
* If this is an array, converts to a list
* If this is a single element, create a list containing this element
* </pre>
*
* @param object input object which needs to be unwinded
* @return a list unwinding the object
*/
public static XList from(Object object) {
if (object == null) {
return null;
}
XList list = new XList();
if (object instanceof Collection) {
Collection l = (Collection) object;
list.addAll(l);
} else if (object instanceof YieldedIterator) {
list.addAll(((YieldedIterator) object).list());
} else if (object.getClass().isArray()) {
Object[] array = getArray(object);
List l = Arrays.asList(array);
list.addAll(l);
} else if (object instanceof Map) {
Map m = ((Map) object);
list = new XList(m);
} else {
list.add(object);
}
return list;
}
/**
* <pre>
* Very important list combine routine
* Given ( arg_0 , arg_1 , arg_2 , ... )
* It would check if arg_xxx is a list type, then would add all element of arg_xxx to the return list.
*
* </pre>
*
* @param args individual objects to be passed
* @return a list combining the unwinded args
*/
public static List combine(Object... args) {
AnonymousParam anon = null;
XList list = new XList();
if (args.length > 1) {
if (args[0] instanceof AnonymousParam) {
anon = (AnonymousParam) args[0];
args = shiftArrayLeft(args, 1);
}
}
for (int i = 0; i < args.length; i++) {
List l = from(args[i]);
if (l != null) {
list.addAll(l);
} else {
list.add(l);
}
}
if (anon != null) {
XList l = new XList();
int i = 0;
for (Object o : list) {
anon.setIterationContextWithPartial(list, o, i, l);
Object ret = anon.execute();
if (ret instanceof JexlException.Continue) {
continue;
}
if (ret instanceof JexlException.Break) {
JexlException.Break br = ((JexlException.Break) ret);
if (br.hasValue) {
l.add(br.value);
}
break;
}
l.add(ret);
i++;
}
list = l;
}
return list;
}
public static List[] partition(Object... args) {
AnonymousParam anon = null;
XList list = new XList();
if (args.length > 1) {
if (args[0] instanceof AnonymousParam) {
anon = (AnonymousParam) args[0];
args = shiftArrayLeft(args, 1);
}
}
for (int i = 0; i < args.length; i++) {
List l = from(args[i]);
list.addAll(l);
}
XList reject = new XList();
if (anon != null) {
XList l = new XList();
int i = 0;
for (Object o : list) {
boolean broken = false;
anon.setIterationContextWithPartial(list, o, i, l);
Object ret = anon.execute();
if (ret instanceof JexlException.Continue) {
JexlException.Continue c = (JexlException.Continue) ret;
//continue exclusive, unless you pass along a value
if (c.hasValue) {
//should add _ITEM_ 's value, if anyone modified it
l.add(anon.getVar(Script._ITEM_));
} else {
reject.add(anon.getVar(Script._ITEM_));
}
continue;
}
if (ret instanceof JexlException.Break) {
JexlException.Break br = (JexlException.Break) ret;
/* breaks inclusive : by default takes the item
unless explicitly specified not to. */
ret = true;
if (br.hasValue) {
ret = br.value;
}
broken = true;
}
if (castBoolean(ret, false)) {
//should add _ITEM_ 's value, if anyone modified it
l.add(anon.getVar(Script._ITEM_));
} else {
reject.add(anon.getVar(Script._ITEM_));
}
if (broken) {
break;
}
i++;
}
list = l;
}
return new XList[]{list, reject};
}
public static List filter(Object... args) {
List[] partition = partition(args);
return partition[0];
}
public static int index(Object... args) {
AnonymousParam anon = null;
XList list = new XList();
if (args.length > 1) {
if (args[0] instanceof AnonymousParam) {
anon = (AnonymousParam) args[0];
args = shiftArrayLeft(args, 1);
}
}
if (args.length < 1) {
return -1;
}
Object item = args[0];
int start = 0;
if (anon == null) {
if (args.length < 2) {
return -1;
}
if (args[1] instanceof CharSequence) {
if (item == null) return -1;
return args[1].toString().indexOf(item.toString());
}
if (JexlArithmetic.areListOrArray(item, args[1])) {
String l = castString(item, SetOperations.SEP);
String r = castString(args[1], SetOperations.SEP);
int inx = r.indexOf(l);
// how many seps are there?
int c = 0;
char sep = SetOperations.SEP.charAt(0);
for (int i = 0; i < inx; i++) {
if (r.charAt(i) == sep) {
c++;
}
}
return inx - c;
}
start = 1;
}
for (int i = start; i < args.length; i++) {
List l = from(args[i]);
if (l == null) continue;
list.addAll(l);
}
if (anon == null) {
return list.indexOf(item);
}
int i = -1;
boolean found = false;
for (Object o : list) {
++i;
anon.setIterationContext(list, o, i);
Object ret = anon.execute();
if (ret instanceof JexlException.Continue) {
if ( ((JexlException.Continue) ret).hasValue ){
found = castBoolean(((JexlException.Continue) ret).value, false);
if ( found ){ return i ;}
}
continue;
}
found = castBoolean(ret, false);
if (found) {
return i;
}
}
return -1;
}
public static int rindex(Object... args) {
AnonymousParam anon = null;
XList list = new XList();
if (args.length > 1) {
if (args[0] instanceof AnonymousParam) {
anon = (AnonymousParam) args[0];
args = shiftArrayLeft(args, 1);
}
}
if (args.length < 1) {
return -1;
}
Object item = args[0];
int start = 0;
if (anon == null) {
if (args.length < 2) {
return -1;
}
if (args[1] instanceof CharSequence) {
if (item == null) return -1;
return args[1].toString().lastIndexOf(item.toString());
}
if (JexlArithmetic.areListOrArray(item, args[1])) {
String l = castString(item, SetOperations.SEP);
String r = castString(args[1], SetOperations.SEP);
if (l.isEmpty()) {
if (args[1] instanceof Collection) {
return ((Collection) args[1]).size() - 1;
}
return Array.getLength(args[1]) - 1;
}
int inx = r.lastIndexOf(l);
// how many seps are there?
int c = 0;
char sep = SetOperations.SEP.charAt(0);
for (int i = 0; i < inx; i++) {
if (r.charAt(i) == sep) {
c++;
}
}
return inx - c;
}
start = 1;
}
for (int i = start; i < args.length; i++) {
List l = from(args[i]);
if (l == null) continue;
list.addAll(l);
}
if (anon == null) {
return list.lastIndexOf(item);
}
int i = list.size() - 1;
boolean found = false;
for (; i >= 0; i--) {
anon.setIterationContext(list, list.get(i), i);
Object ret = anon.execute();
if (ret instanceof JexlException.Continue) {
if ( ((JexlException.Continue) ret).hasValue ){
found = castBoolean(((JexlException.Continue) ret).value, false);
if ( found ){ return i ; }
}
continue;
}
found = castBoolean(ret, false);
if (found) {
return i ;
}
}
return -1;
}
public static Iterator range(Object... args) throws Exception {
if (args.length == 0) {
return new RangeIterator();
}
long end = 42;
long start = 1;
if (args.length > 0) {
if (args[0] instanceof Date || args[0] instanceof DateTime) {
// a different iterator ...
DateTime et = castTime(args[0]);
if (args.length > 1) {
if (args[1] instanceof Date || args[1] instanceof DateTime) {
DateTime st = castTime(args[1]);
if (args.length > 2) {
String d = args[2].toString();
try {
long dur = Long.parseLong(d);
return new DateIterator(et, st, new Duration(dur));
} catch (Exception e) {
return new DateIterator(et, st, new Duration(DateIterator.parseDuration(d)));
}
}
return new DateIterator(et, st);
}
}
return new DateIterator(et);
}
if (args[0] instanceof String || args[0] instanceof Character) {
// a different iterator ...
Character et = castChar(args[0]);
if (args.length > 1) {
if (args[1] instanceof String || args[1] instanceof Character) {
Character st = castChar(args[1]);
if (args.length > 2) {
String d = args[2].toString();
try {
short dur = Short.parseShort(d);
return new SymbolIterator(et, st, dur);
} catch (Exception e) {
return new SymbolIterator(et, st, (short) 1);
}
}
return new SymbolIterator(et, st);
}
}
return new SymbolIterator(et);
}
end = Long.valueOf(args[0].toString());
if (args.length > 1) {
start = Long.valueOf(args[1].toString());
if (args.length > 2) {
long space = Long.valueOf(args[2].toString());
return new RangeIterator(end, start, space);
}
}
}
return new RangeIterator(end, start);
}
public static Object[] shiftArrayLeft(Object[] args, int shift) {
Object[] array = new Object[args.length - shift];
for (int i = 0; i < array.length; i++) {
array[i] = args[i + shift];
}
return array;
}
public static ListSet set(Object... args) {
List list = combine(args);
ListSet set = new ListSet();
set.addAll(list);
return set;
}
public static Object[] minmax(Object... args) throws Exception {
if (args.length == 0) return null;
if (args[0] instanceof AnonymousParam) {
AnonymousParam anon = (AnonymousParam) args[0];
args = shiftArrayLeft(args, 1);
List l = combine(args);
if (l.size() == 0) return null;
Object min = l.get(0);
Object max = min;
for (int i = 1; i < l.size(); i++) {
Object item = l.get(i);
AnonymousComparator cmp = new AnonymousComparator(anon, l, false);
int cmpResult = cmp.compare(item, min);
if (cmpResult < 0) {
// i.e. item < min, hence change min
min = item;
continue;
}
cmpResult = cmp.compare(item, max);
if (cmpResult > 0) {
// i.e. item > max, hence change max
max = item;
}
}
Object[] container = new Object[]{min, max};
return container;
}
List l = combine(args);
if (l.size() == 0) return null;
Object min = l.get(0);
Object max = min;
for (int i = 1; i < l.size(); i++) {
Comparable item = (Comparable) l.get(i);
if (item.compareTo(min) < 0) {
min = item;
}
if (item.compareTo(max) > 0) {
max = item;
}
}
Object[] container = new Object[]{min, max};
return container;
}
public static Map obj2dict(Object o) throws Exception {
Map fm = (Map) inspect(o);
List<XList.Pair> iFields = (List) fm.get("f");
Map omap = new HashMap<>();
omap.put("@t", o.getClass().getName());
for (XList.Pair f : iFields) {
String n = String.valueOf(f.getKey());
Field field = introspector.getField(o.getClass(), n);
Object value = field.get(o);
omap.put(n, value);
}
return Collections.unmodifiableMap(omap);
}
public static Heap makeHeap(Object... args) throws Exception {
if (args.length == 0) throw new Exception("Unspecified heap size!");
if (args.length == 1) return new Heap(castInteger(args[0]));
if (args[0] instanceof AnonymousParam) {
AnonymousComparator comparator = new AnonymousComparator((AnonymousParam) args[0], null, false);
int s = castInteger(args[1]);
return new Heap(s, comparator);
}
if (args[1] instanceof Boolean) {
return new Heap(castInteger(args[0]), (Boolean) args[1]);
}
return new Heap(castInteger(args[0]), (Comparator) args[1]);
}
public static Map makeDict(Object... args) throws Exception {
HashMap map = new HashMap();
// empty dict
if (args.length == 0) {
return map;
}
// clone the dict
if (args.length == 1 && args[0] instanceof Map) {
map.putAll((Map) args[0]);
return map;
}
if (args[0] instanceof AnonymousParam) {
// now what we do?
AnonymousParam anon = (AnonymousParam) args[0];
args = shiftArrayLeft(args, 1);
if (args.length == 1) {
List list = from(args[0]);
for (int i = 0; i < list.size(); i++) {
Object o = list.get(i);
anon.setIterationContextWithPartial(list, o, i, map);
Object ret = anon.execute();
if (ret == null) {
map.put(o, null);
} else if (ret instanceof Map) {
map.putAll((Map) ret);
} else if (ret.getClass().isArray()) {
Object key = Array.get(ret, 0);
Object value = Array.get(ret, 1);
map.put(key, value);
}
}
} else {
List keyList = from(args[0]);
List valueList = from(args[1]);
if (keyList.size() != valueList.size()) {
return map;
}
int size = keyList.size();
for (int i = 0; i < size; i++) {
Object k = keyList.get(i);
Object v = valueList.get(i);
anon.setIterationContextWithPartial(new Object[]{keyList, valueList}
, new Object[]{k, v}, i, map);
Object ret = anon.execute();
if (ret == null) {
break;
}
if (ret instanceof Map) {
map.putAll((Map) ret);
} else if (ret.getClass().isArray()) {
Object key = Array.get(ret, 0);
Object value = Array.get(ret, 1);
map.put(key, value);
}
}
}
return map;
}
// in case the sizes do not match at all...
if (args.length % 2 == 1) {
// return a map representing a complex object
return obj2dict(args[0]);
}
List keyList = from(args[0]);
List valueList = from(args[1]);
if (keyList.size() != valueList.size()) {
throw new Exception("Key and Value Arrays/Lists are not of same length!");
}
for (int i = 0; i < keyList.size(); i++) {
map.put(keyList.get(i), valueList.get(i));
}
return map;
}
public static Object[] sqlmath(Object... argv) {
Object[] math = new Object[]{null, null, null};
JexlArithmetic arithmetic = new JexlArithmetic(false);
List list = combine(argv);
if (list.size() > 0) {
int index = 0;
Object obj = list.get(index);
math[0] = obj;
math[1] = math[0];
math[2] = math[0];
for (index = 1; index < list.size(); index++) {
obj = list.get(index);
if (arithmetic.lessThan(obj, math[0])) {
math[0] = obj; // MIN
}
if (arithmetic.greaterThan(obj, math[1])) {
math[1] = obj; // MAX
}
math[2] = arithmetic.add(math[2], obj); // SUM
}
}
return math;
}
public static void bye(Object... args) {
String msg = "BYE received, we will exit this script...";
Integer exitStatus = null;
System.out.println(Main.strArr(args));
if (args.length > 1 && args[0] instanceof Number) {
exitStatus = ((Number) args[0]).intValue();
}
if (exitStatus != null) {
System.exit(exitStatus);
}
JexlNode node = new ASTReturnStatement(Parser.JJTARRAYLITERAL);
JexlNode child = new ASTStringLiteral(Parser.STRING_LITERAL);
child.image = "__bye__";
node.jjtAddChild(child, 0);
throw new JexlException.Return(node, msg, args);
}
public static boolean test(Object... args) {
if (args.length == 0) {
return true;
}
boolean ret;
Object args0 = args[0];
args = shiftArrayLeft(args, 1);
if (args0 instanceof AnonymousParam) {
((AnonymousParam) args0).setIterationContext(args, args, 0);
try {
Object o = ((AnonymousParam) args0).execute();
ret = castBoolean(o);
} catch (Throwable t) {
ret = false;
}
} else {
ret = castBoolean(args0, false);
}
if (!ret) {
bye(args);
}
// log it - later problem - not now
return ret;
}
public static boolean error(Object... args) {
if (args.length == 0) {
return false;
}
Object args0 = args[0];
if (args0 instanceof String) {
throw new Error(String.valueOf(args0));
}
boolean ret;
args = shiftArrayLeft(args, 1);
if (args0 instanceof AnonymousParam) {
((AnonymousParam) args0).setIterationContext(args, args, 0);
try {
Object o = ((AnonymousParam) args0).execute();
ret = castBoolean(o);
} catch (Throwable t) {
ret = false;
}
} else {
ret = castBoolean(args0, false);
}
if (ret) {
if (args.length > 0) {
if (args[0] instanceof Error) {
throw (Error) args[0];
}
if (args[0] instanceof Throwable) {
throw new Error((Throwable) args[0]);
}
throw new Error(castString(args[0]));
}
throw new Error("Caused by *error* ");
}
// log it - later problem - not now
return false;
}
public static Object[] array(Object... args) {
List l = combine(args);
Object[] a = new Object[l.size()];
l.toArray(a);
return a;
}
public static class AnonymousComparator implements Comparator {
public final AnonymousParam anon;
public final Object collection;
public final boolean reverse;
public AnonymousComparator(AnonymousParam anon, Object collection, boolean reverse) {
this.anon = anon;
this.collection = collection;
this.reverse = reverse;
}
@Override
public int compare(Object o1, Object o2) {
Object[] pair = new Object[]{o1, o2};
anon.setIterationContext(collection, pair, -1);
Object ret = anon.execute();
if (ret instanceof Number) {
int i = ((Comparable) ret).compareTo(0);
return i;
}
boolean smaller = castBoolean(ret, false);
if (reverse) {
if (smaller) {
return 1;
}
return -1;
}
if (smaller) {
return -1;
}
return 1; // unstable... but fine I suppose
}
}
public static Object ascending(Object... args) {
if (args.length == 0) {
return Collections.emptyList();
}
boolean isArray = false;
Object l;
if (args.length > 0) {
if (args[0] instanceof AnonymousParam) {
AnonymousParam anon = (AnonymousParam) args[0];
args = shiftArrayLeft(args, 1);
if (args.length == 1 && args[0] != null && args[0].getClass().isArray()) {
l = array(args[0]);
isArray = true;
} else {
l = combine(args);
}
AnonymousComparator comparator = new AnonymousComparator(anon, l, false);
if (isArray) {
Arrays.sort((Object[]) l, comparator);
} else {
Collections.sort((List) l, comparator);
}
return l;
}
}
if (args.length == 1 && args[0] != null && args[0].getClass().isArray()) {
l = array(args[0]);
Arrays.sort((Object[]) l);
} else {
l = combine(args);
Collections.sort((List) l);
}
return l;
}
public static Object descending(Object... args) {
if (args.length == 0) {
return Collections.emptyList();
}
boolean isArray = false;
Object l;
if (args.length > 0) {
if (args[0] instanceof AnonymousParam) {
AnonymousParam anon = (AnonymousParam) args[0];
args = shiftArrayLeft(args, 1);
if (args.length == 1 && args[0] != null && args[0].getClass().isArray()) {
l = array(args[0]);
isArray = true;
} else {
l = combine(args);
}
AnonymousComparator comparator = new AnonymousComparator(anon, l, true);
if (isArray) {
Arrays.sort((Object[]) l, comparator);
} else {
Collections.sort((List) l, comparator);
}
return l;
}
}
if (args.length == 1 && args[0] != null && args[0].getClass().isArray()) {
l = array(args[0]);
Arrays.sort((Object[]) l, Collections.reverseOrder());
} else {
l = combine(args);
Collections.sort((List) l, Collections.reverseOrder());
}
return l;
}
public static Object guardedBlock(Object... args) {
if (args.length == 0) {
return null;
}
if (!(args[0] instanceof AnonymousParam)) {
return args[0];
}
AnonymousParam anon = (AnonymousParam) args[0];
args = shiftArrayLeft(args, 1);
try {
Object r = anon.execute();
return r;
} catch (Throwable throwable) {
if (args.length == 0) {
Throwable ret = throwable.getCause();
if ( ret != null ) { return ret ; }
return throwable ;
}
return args[0];
}
}
public static boolean wait(Object... args) throws Exception {
int pollInterval = 100; // in ms
int duration = 3000; // in ms
if (args.length == 0) {
Thread.sleep(duration);
return true;
}
AnonymousParam anon = null;
if (args[0] instanceof AnonymousParam) {
anon = (AnonymousParam) args[0];
args = shiftArrayLeft(args, 1);
}
if (args.length > 0) {
duration = castInteger(args[0], duration);
if (anon == null) {
Thread.sleep(duration);
return true;
}
if (args.length > 1) {
pollInterval = castInteger(args[1], pollInterval);
}
}
long start = System.currentTimeMillis();
while (true) {
try {
Thread.sleep(pollInterval);
Object er = anon.execute();
boolean ret = castBoolean(er, false);
if (ret) return true;
} catch (Throwable throwable) {
// do nothing
}
long cur = System.currentTimeMillis();
if (cur - start > duration) break;
}
return false;
}
public static Object interceptCastingCall(String methodName, Object[] argv, Boolean[] success) throws Exception {
if (success != null) {
success[0] = true;
}
// when length is non zero and last arg is this __args__ then we are overwriting
if (argv.length > 0 && argv[argv.length - 1] instanceof Interpreter.NamedArgs) {
Interpreter.NamedArgs na = (Interpreter.NamedArgs) argv[argv.length - 1];
if (!Script.ARGS.equals(na.name)) {
throw new Exception("Named Args is not " + Script.ARGS);
}
Object[] args = array(na.value);
if (argv.length == 2 && argv[0] instanceof AnonymousParam) {
AnonymousParam anon = (AnonymousParam) argv[0];
argv = new Object[args.length + 1];
argv[0] = anon;
for (int i = 1; i < argv.length; i++) {
argv[i] = args[i - 1];
}
} else {
// overwrite everything
argv = args;
}
}
switch (methodName) {
case TYPE:
return type(argv);
case BYTE:
return castByte(argv);
case CHAR:
return castChar(argv);
case SHORT:
return castShort(argv);
case ENUM:
return castEnum(argv);
case INT:
return castInteger(argv);
case LONG:
return castLong(argv);
case FLOAT:
return castFloat(argv);
case DOUBLE:
return castDouble(argv);
case BIGDECIMAL:
return castBigDecimal(argv);
case BIGINT:
return castBigInteger(argv);
case BOOL:
return castBoolean(argv);
case STRING:
return castString(argv);
case TIME:
return castTime(argv);
case DATE:
return castDate(argv);
case INSTANT:
return castInstant(argv);
case LITERAL_LIST:
return makeLiteralList(argv);
case LIST:
return combine(argv);
case PROJECT:
case SUBLIST:
return sublist(argv);
case FILTER:
case SELECT:
return filter(argv);
case PARTITION:
return partition(argv);
case FIND:
case INDEX:
return index(argv);
case RINDEX:
return rindex(argv);
case JOIN:
return SetOperations.join_c(argv);
case ARRAY:
return array(argv);
case SET:
return set(argv);
case DICTIONARY:
return makeDict(argv);
case HEAP:
return makeHeap(argv);
case RANGE:
return range(argv);
case ARRAY_FROM_LIST:
return getArray(makeLiteralList(argv));
case MINMAX:
return minmax(argv);
case SQLMATH:
return sqlmath(argv);
case READ:
return read(argv);
case READ_LINES:
return readLines(argv);
case WRITE:
case PRINT:
return writeFile(argv);
case SEND:
return send(argv);
case BYE:
bye(argv);
break;
case ASSERT:
case TEST:
return test(argv);
case ERROR:
return error(argv);
case LOAD_PATH:
return ReflectionUtility.load_path(argv);
case JSON:
return json(argv);
case XML:
return xml(argv);
case MULTI_SET1:
case MULTI_SET2:
case MULTI_SET3:
return SetOperations.multiset(argv);
case SORT_ASCENDING:
return ascending(argv);
case SORT_DESCENDING:
return descending(argv);
case TRY:
return guardedBlock(argv);
case POLL:
return wait(argv);
case SYSTEM:
return system(argv);
case SHUFFLE:
return shuffle(argv);
case RANDOM:
return random(argv);
case THREAD:
return thread(argv);
case LEFT_FOLD:
return fold(false, argv);
case RIGHT_FOLD:
return fold(true, argv);
case TOKEN:
return tokenize(argv);
case HASH:
return hash(argv);
case FOPEN:
return fopen(argv);
case MATRIX:
return matrix(argv);
case DATABASE:
return dataBase(argv);
case INSPECT:
return inspect(argv);
case ATOMIC:
return atomic(argv);
case COUNTABLE:
return Z(argv);
case RATIONAL:
return Q(argv);
case NUMBER:
return NUM(argv);
default:
if (success != null) {
success[0] = false;
}
break;
}
return methodName;
}
private static Object castEnum(Object... argv) {
if (argv.length == 0) return null;
try {
EnumWrapper w = EnumWrapper.enumWrapper(argv[0]);
if (argv.length > 1) {
return w.get(argv[1]);
}
return w;
} catch (Exception e) {
}
return null;
}
private static Object sublist(Object... args) {
if (args.length == 0) {
return null;
}
boolean charSequence = false;
if (args[0] instanceof CharSequence) {
args[0] = String.valueOf(args[0]).toCharArray();
charSequence = true;
}
List l = from(args[0]);
int start = 0;
int end = l.size() - 1;
if (args.length > 1) {
start = castInteger(args[1], start);
if (args.length > 2) {
end = castInteger(args[2], end);
}
if (start < 0 && end < 0) {
end = l.size() - 1 + end;
start = l.size() - 1 + start;
} else if (end < 0) {
end = l.size() - 1 + end;
} else if (start < 0) {
end = l.size() - 1 + start;
start = 0;
}
}
XList r = new XList();
for (int i = start; i <= end; i++) {
r.add(l.get(i));
}
if (args[0].getClass().isArray()) {
if (charSequence) return castString(r, "");
return r.toArray();
}
return r;
}
public static Object system(Object... args) throws Exception {
if (args.length == 0) return Runtime.getRuntime();
Process p = null;
if (args.length == 1) {
p = Runtime.getRuntime().exec(args[0].toString());
} else {
String[] params = new String[args.length];
for (int i = 0; i < params.length; i++) {
params[i] = String.valueOf(args[i]);
}
p = Runtime.getRuntime().exec(params);
}
if (p == null) return 255;
p.waitFor();
// terrible nomenclature in Java
BufferedReader or = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader er = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String line;
while ((line = or.readLine()) != null) {
System.out.println(line);
}
while ((line = er.readLine()) != null) {
System.err.println(line);
}
return p.exitValue();
}
public static synchronized Thread thread(Object... args) throws Exception {
if (args.length == 0) {
return Thread.currentThread();
}
if (args[0] instanceof AnonymousParam) {
AnonymousParam anonymousParam = (AnonymousParam) args[0];
args = shiftArrayLeft(args, 1);
Thread t = new Thread(anonymousParam);
anonymousParam.setIterationContext(args, t, t.getId());
t.start();
return t;
}
return Thread.currentThread();
}
}