/**
* Copyright (c) 2014, the Railo Company Ltd.
* Copyright (c) 2015, Lucee Assosication Switzerland
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
package lucee.commons.io;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryType;
import java.lang.management.MemoryUsage;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.NetworkInterface;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.ServletContext;
import lucee.commons.digest.MD5;
import lucee.commons.io.log.Log;
import lucee.commons.io.log.LogUtil;
import lucee.commons.io.res.Resource;
import lucee.commons.io.res.ResourceProvider;
import lucee.commons.io.res.ResourcesImpl;
import lucee.commons.io.res.util.ResourceUtil;
import lucee.commons.lang.CharSet;
import lucee.commons.lang.ClassLoaderHelper;
import lucee.commons.lang.ClassUtil;
import lucee.commons.lang.ExceptionUtil;
import lucee.commons.lang.StringUtil;
import lucee.commons.lang.types.RefInteger;
import lucee.commons.lang.types.RefIntegerImpl;
import lucee.loader.TP;
import lucee.loader.engine.CFMLEngineFactory;
import lucee.runtime.PageContext;
import lucee.runtime.PageContextImpl;
import lucee.runtime.PageSource;
import lucee.runtime.PageSourceImpl;
import lucee.runtime.config.Config;
import lucee.runtime.engine.InfoImpl;
import lucee.runtime.exp.ApplicationException;
import lucee.runtime.exp.DatabaseException;
import lucee.runtime.functions.other.CreateUniqueId;
import lucee.runtime.net.http.ReqRspUtil;
import lucee.runtime.op.Caster;
import lucee.runtime.osgi.OSGiUtil;
import lucee.runtime.type.Array;
import lucee.runtime.type.Collection;
import lucee.runtime.type.KeyImpl;
import lucee.runtime.type.Query;
import lucee.runtime.type.QueryImpl;
import lucee.runtime.type.Struct;
import lucee.runtime.type.StructImpl;
import lucee.runtime.type.util.KeyConstants;
import lucee.runtime.type.util.ListUtil;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleReference;
import com.jezhumble.javasysmon.CpuTimes;
import com.jezhumble.javasysmon.JavaSysMon;
import com.jezhumble.javasysmon.MemoryStats;
/**
*
*/
public final class SystemUtil {
public static final int MEMORY_TYPE_ALL=lucee.runtime.util.SystemUtil.MEMORY_TYPE_ALL;
public static final int MEMORY_TYPE_HEAP=lucee.runtime.util.SystemUtil.MEMORY_TYPE_HEAP;
public static final int MEMORY_TYPE_NON_HEAP=lucee.runtime.util.SystemUtil.MEMORY_TYPE_NON_HEAP;
public static final int ARCH_UNKNOW=lucee.runtime.util.SystemUtil.ARCH_UNKNOW;
public static final int ARCH_32=lucee.runtime.util.SystemUtil.ARCH_32;
public static final int ARCH_64=lucee.runtime.util.SystemUtil.ARCH_64;
public static final String SETTING_CONTROLLER_DISABLED = "lucee.controller.disabled";
public static final char CHAR_DOLLAR=(char)36;
public static final char CHAR_POUND=(char)163;
public static final char CHAR_EURO=(char)8364;
public static final int JAVA_VERSION_1_0 = lucee.runtime.util.SystemUtil.JAVA_VERSION_1_0;
public static final int JAVA_VERSION_1_1 = lucee.runtime.util.SystemUtil.JAVA_VERSION_1_1;
public static final int JAVA_VERSION_1_2 = lucee.runtime.util.SystemUtil.JAVA_VERSION_1_2;
public static final int JAVA_VERSION_1_3 = lucee.runtime.util.SystemUtil.JAVA_VERSION_1_3;
public static final int JAVA_VERSION_1_4 = lucee.runtime.util.SystemUtil.JAVA_VERSION_1_4;
public static final int JAVA_VERSION_1_5 = lucee.runtime.util.SystemUtil.JAVA_VERSION_1_5;
public static final int JAVA_VERSION_1_6 = lucee.runtime.util.SystemUtil.JAVA_VERSION_1_6;
public static final int JAVA_VERSION_1_7 = lucee.runtime.util.SystemUtil.JAVA_VERSION_1_7;
public static final int JAVA_VERSION_1_8 = lucee.runtime.util.SystemUtil.JAVA_VERSION_1_8;
public static final int JAVA_VERSION_1_9 = lucee.runtime.util.SystemUtil.JAVA_VERSION_1_9;
public static final int OUT = lucee.runtime.util.SystemUtil.OUT;
public static final int ERR = lucee.runtime.util.SystemUtil.ERR;
private static final PrintWriter PRINTWRITER_OUT = new PrintWriter(System.out);
private static final PrintWriter PRINTWRITER_ERR = new PrintWriter(System.err);
private static PrintWriter[] printWriter=new PrintWriter[2];
public static final char SYMBOL_EURO = "\u20ac".charAt(0);
public static final char SYMBOL_POUND = "\u00a3".charAt(0);
public static final char SYMBOL_MICRO = "\u03bc".charAt(0);
public static final char SYMBOL_A_RING = "\u00e5".charAt(0);
private static final boolean isWindows;
private static final boolean isSolaris;
private static final boolean isLinux;
private static final boolean isMacOSX;
private static final boolean isUnix;
private static Resource homeFile;
private static Resource[] classPathes;
private static CharSet charset;
private static String lineSeparator=System.getProperty("line.separator","\n");
private static MemoryPoolMXBean permGenSpaceBean;
public static int osArch=-1;
public static int jreArch=-1;
private static final String JAVA_VERSION_STRING = System.getProperty("java.version");
public static final int JAVA_VERSION;
static {
// OS
String os = System.getProperty("os.name").toLowerCase();
isWindows=os.startsWith("windows");
isSolaris=os.startsWith("solaris");
isLinux=os.startsWith("linux");
isMacOSX=os.startsWith("mac os x");
isUnix=!isWindows && File.separatorChar == '/'; // deprecated
String strCharset=System.getProperty("file.encoding");
if(strCharset==null || strCharset.equalsIgnoreCase("MacRoman"))
strCharset="cp1252";
if(strCharset.equalsIgnoreCase("utf-8")) charset=CharSet.UTF8;
else if(strCharset.equalsIgnoreCase("iso-8859-1")) charset=CharSet.ISO88591;
else charset=CharsetUtil.toCharSet(strCharset,null);
// Perm Gen
permGenSpaceBean=getPermGenSpaceBean();
// make sure the JVM does not always a new bean
MemoryPoolMXBean tmp = getPermGenSpaceBean();
if(tmp!=permGenSpaceBean)permGenSpaceBean=null;
if(JAVA_VERSION_STRING.startsWith("1.9.")) JAVA_VERSION=JAVA_VERSION_1_9;
else if(JAVA_VERSION_STRING.startsWith("1.8.")) JAVA_VERSION=JAVA_VERSION_1_8;
else if(JAVA_VERSION_STRING.startsWith("1.7.")) JAVA_VERSION=JAVA_VERSION_1_7;
else if(JAVA_VERSION_STRING.startsWith("1.6.")) JAVA_VERSION=JAVA_VERSION_1_6;
else if(JAVA_VERSION_STRING.startsWith("1.5.")) JAVA_VERSION=JAVA_VERSION_1_5;
else if(JAVA_VERSION_STRING.startsWith("1.4.")) JAVA_VERSION=JAVA_VERSION_1_4;
else if(JAVA_VERSION_STRING.startsWith("1.3.")) JAVA_VERSION=JAVA_VERSION_1_3;
else if(JAVA_VERSION_STRING.startsWith("1.2.")) JAVA_VERSION=JAVA_VERSION_1_2;
else if(JAVA_VERSION_STRING.startsWith("1.1.")) JAVA_VERSION=JAVA_VERSION_1_1;
else JAVA_VERSION=JAVA_VERSION_1_0;
}
private static ClassLoader loaderCL;
private static ClassLoader coreCL;
public static ClassLoader getLoaderClassLoader() {
if(loaderCL==null)
loaderCL=new TP().getClass().getClassLoader();
return loaderCL;
}
public static ClassLoader getCoreClassLoader() {
if(coreCL==null)
coreCL=new ClassLoaderHelper().getClass().getClassLoader();
return coreCL;
}
public static MemoryPoolMXBean getPermGenSpaceBean() {
java.util.List<MemoryPoolMXBean> manager = ManagementFactory.getMemoryPoolMXBeans();
MemoryPoolMXBean bean;
// PERM GEN
Iterator<MemoryPoolMXBean> it = manager.iterator();
while(it.hasNext()){
bean = it.next();
if("Perm Gen".equalsIgnoreCase(bean.getName()) || "CMS Perm Gen".equalsIgnoreCase(bean.getName())) {
return bean;
}
}
it = manager.iterator();
while(it.hasNext()){
bean = it.next();
if(StringUtil.indexOfIgnoreCase(bean.getName(),"Perm Gen")!=-1 || StringUtil.indexOfIgnoreCase(bean.getName(),"PermGen")!=-1) {
return bean;
}
}
// take none-heap when only one
it = manager.iterator();
LinkedList<MemoryPoolMXBean> beans=new LinkedList<MemoryPoolMXBean>();
while(it.hasNext()){
bean = it.next();
if(bean.getType().equals(MemoryType.NON_HEAP)) {
beans.add(bean);
return bean;
}
}
if(beans.size()==1) return beans.getFirst();
// Class Memory/ClassBlock Memory?
it = manager.iterator();
while(it.hasNext()){
bean = it.next();
if(StringUtil.indexOfIgnoreCase(bean.getName(),"Class Memory")!=-1) {
return bean;
}
}
return null;
}
private static Boolean isFSCaseSensitive;
private static JavaSysMon jsm;
private static Boolean isCLI;
private static double loaderVersion=0D;
private static boolean hasMacAddress;
private static String macAddress;
/**
* returns if the file system case sensitive or not
* @return is the file system case sensitive or not
*/
public static boolean isFSCaseSensitive() {
if(isFSCaseSensitive==null) {
try {
_isFSCaseSensitive(File.createTempFile("abcx","txt"));
}
catch (IOException e) {
File f = new File("abcx.txt").getAbsoluteFile();
try {
f.createNewFile();
_isFSCaseSensitive(f);
} catch (IOException e1) {
throw new RuntimeException(e1.getMessage());
}
}
}
return isFSCaseSensitive.booleanValue();
}
private static void _isFSCaseSensitive(File f) {
File temp=new File(f.getPath().toUpperCase());
isFSCaseSensitive=temp.exists()?Boolean.FALSE:Boolean.TRUE;
f.delete();
}
/**
* fixes a java canonical path to a Windows path
* e.g. /C:/Windows/System32 will be changed to C:\Windows\System32
*
* @param path
* @return
*/
public static String fixWindowsPath(String path) {
if ( isWindows && path.length() > 3 && path.charAt(0) == '/' && path.charAt(2) == ':' ) {
path = path.substring(1).replace( '/', '\\' );
}
return path;
}
/**
* @return is local machine a Windows Machine
*/
public static boolean isWindows() {
return isWindows;
}
/**
* @return is local machine a Linux Machine
*/
public static boolean isLinux() {
return isLinux;
}
/**
* @return is local machine a Solaris Machine
*/
public static boolean isSolaris() {
return isSolaris;
}
/**
* @return is local machine a Solaris Machine
*/
public static boolean isMacOSX() {
return isMacOSX;
}
/**
* @return is local machine a Unix Machine
*/
public static boolean isUnix() {
return isUnix;
}
/**
* returns the Temp Directory of the System
* @return temp directory
* @throws IOException
*/
public static Resource getTempDirectory() {
return ResourcesImpl.getFileResourceProvider().getResource(CFMLEngineFactory.getTempDirectory().getAbsolutePath());
/*if(tempFile!=null) return tempFile;
ResourceProvider fr = ResourcesImpl.getFileResourceProvider();
String tmpStr = System.getProperty("java.io.tmpdir");
if(tmpStr!=null) {
tempFile=fr.getResource(tmpStr);
if(tempFile.exists()) {
tempFile=ResourceUtil.getCanonicalResourceEL(tempFile);
return tempFile;
}
}
File tmp =null;
try {
tmp = File.createTempFile("a","a");
tempFile=fr.getResource(tmp.getParent());
tempFile=ResourceUtil.getCanonicalResourceEL(tempFile);
}
catch(IOException ioe) {}
finally {
if(tmp!=null)tmp.delete();
}
return tempFile;*/
}
/**
* returns the a unique temp file (with no auto delete)
* @param extension
* @return temp directory
* @throws IOException
*/
public static Resource getTempFile(String extension, boolean touch) throws IOException {
String filename=CreateUniqueId.invoke();
if(!StringUtil.isEmpty(extension,true)){
if(extension.startsWith("."))filename+=extension;
else filename+="."+extension;
}
Resource file = getTempDirectory().getRealResource(filename);
if(touch)ResourceUtil.touch(file);
return file;
}
/**
* @return return System directory
*/
public static Resource getSystemDirectory() {
return ResourcesImpl.getFileResourceProvider().getResource(CFMLEngineFactory.getSystemDirectory().getAbsolutePath());
/*String pathes=System.getProperty("java.library.path");
ResourceProvider fr = ResourcesImpl.getFileResourceProvider();
if(pathes!=null) {
String[] arr=ListUtil.toStringArrayEL(ListUtil.listToArray(pathes,File.pathSeparatorChar));
for(int i=0;i<arr.length;i++) {
if(arr[i].toLowerCase().indexOf("windows\\system")!=-1) {
Resource file = fr.getResource(arr[i]);
if(file.exists() && file.isDirectory() && file.isWriteable()) return ResourceUtil.getCanonicalResourceEL(file);
}
}
for(int i=0;i<arr.length;i++) {
if(arr[i].toLowerCase().indexOf("windows")!=-1) {
Resource file = fr.getResource(arr[i]);
if(file.exists() && file.isDirectory() && file.isWriteable()) return ResourceUtil.getCanonicalResourceEL(file);
}
}
for(int i=0;i<arr.length;i++) {
if(arr[i].toLowerCase().indexOf("winnt")!=-1) {
Resource file = fr.getResource(arr[i]);
if(file.exists() && file.isDirectory() && file.isWriteable()) return ResourceUtil.getCanonicalResourceEL(file);
}
}
for(int i=0;i<arr.length;i++) {
if(arr[i].toLowerCase().indexOf("win")!=-1) {
Resource file = fr.getResource(arr[i]);
if(file.exists() && file.isDirectory() && file.isWriteable()) return ResourceUtil.getCanonicalResourceEL(file);
}
}
for(int i=0;i<arr.length;i++) {
Resource file = fr.getResource(arr[i]);
if(file.exists() && file.isDirectory() && file.isWriteable()) return ResourceUtil.getCanonicalResourceEL(file);
}
}
return null;*/
}
/**
* @return return running context root
*/
public static Resource getRuningContextRoot() {
ResourceProvider frp = ResourcesImpl.getFileResourceProvider();
try {
return frp.getResource(".").getCanonicalResource();
} catch (IOException e) {}
URL url=InfoImpl.class.getClassLoader().getResource(".");
try {
return frp.getResource(FileUtil.URLToFile(url).getAbsolutePath());
} catch (MalformedURLException e) {
return null;
}
}
/**
* returns the Hoome Directory of the System
* @return home directory
*/
public static Resource getHomeDirectory() {
if(homeFile!=null) return homeFile;
ResourceProvider frp = ResourcesImpl.getFileResourceProvider();
String homeStr = System.getProperty("user.home");
if(homeStr!=null) {
homeFile=frp.getResource(homeStr);
homeFile=ResourceUtil.getCanonicalResourceEL(homeFile);
}
return homeFile;
}
public static Resource getClassLoaderDirectory(){
return ResourceUtil.toResource(CFMLEngineFactory.getClassLoaderRoot(TP.class.getClassLoader()));
}
/**
* get class pathes from all url ClassLoaders
* @param ucl URL Class Loader
* @param pathes Hashmap with allpathes
*/
private static void getClassPathesFromClassLoader(URLClassLoader ucl, ArrayList<Resource> pathes) {
ClassLoader pcl=ucl.getParent();
// parent first
if(pcl instanceof URLClassLoader)
getClassPathesFromClassLoader((URLClassLoader) pcl, pathes);
ResourceProvider frp = ResourcesImpl.getFileResourceProvider();
// get all pathes
URL[] urls=ucl.getURLs();
for(int i=0;i<urls.length;i++) {
Resource file=frp.getResource(urls[i].getPath());
if(file.exists())
pathes.add(ResourceUtil.getCanonicalResourceEL(file));
}
}
/**
* @return returns a string list of all pathes
*/
public static Resource[] getClassPathes() {
if(classPathes!=null)
return classPathes;
ArrayList<Resource> pathes=new ArrayList<Resource>();
String pathSeperator=System.getProperty("path.separator");
if(pathSeperator==null)pathSeperator=";";
// java.ext.dirs
ResourceProvider frp = ResourcesImpl.getFileResourceProvider();
// pathes from system properties
String strPathes=System.getProperty("java.class.path");
if(strPathes!=null) {
Array arr=ListUtil.listToArrayRemoveEmpty(strPathes,pathSeperator);
int len=arr.size();
for(int i=1;i<=len;i++) {
Resource file=frp.getResource(Caster.toString(arr.get(i,""),"").trim());
if(file.exists())
pathes.add(ResourceUtil.getCanonicalResourceEL(file));
}
}
// pathes from url class Loader (dynamic loaded classes)
ClassLoader cl = InfoImpl.class.getClassLoader();
if(cl instanceof URLClassLoader)
getClassPathesFromClassLoader((URLClassLoader) cl, pathes);
return classPathes=(Resource[]) pathes.toArray(new Resource[pathes.size()]);
}
public static long getUsedMemory() {
Runtime r = Runtime.getRuntime();
return r.totalMemory()-r.freeMemory();
}
public static long getAvailableMemory() {
Runtime r = Runtime.getRuntime();
return r.freeMemory();
}
/**
* replace path placeholder with the real path, placeholders are [{temp-directory},{system-directory},{home-directory}]
* @param path
* @return updated path
*/
public static String parsePlaceHolder(String path) {
return CFMLEngineFactory.parsePlaceHolder(path);
}
public static String addPlaceHolder(Resource file, String defaultValue) {
// Temp
String path=addPlaceHolder(getTempDirectory(),file,"{temp-directory}");
if(!StringUtil.isEmpty(path)) return path;
// System
path=addPlaceHolder(getSystemDirectory(),file,"{system-directory}");
if(!StringUtil.isEmpty(path)) return path;
// Home
path=addPlaceHolder(getHomeDirectory(),file,"{home-directory}");
if(!StringUtil.isEmpty(path)) return path;
return defaultValue;
}
private static String addPlaceHolder(Resource dir, Resource file,String placeholder) {
if(ResourceUtil.isChildOf(file, dir)){
try {
return StringUtil.replace(file.getCanonicalPath(), dir.getCanonicalPath(), placeholder, true);
}
catch (IOException e) {}
}
return null;
}
public static String addPlaceHolder(Resource file, Config config, String defaultValue) {
//ResourceProvider frp = ResourcesImpl.getFileResourceProvider();
// temp
Resource dir = config.getTempDirectory();
String path = addPlaceHolder(dir,file,"{temp-directory}");
if(!StringUtil.isEmpty(path)) return path;
// Config
dir = config.getConfigDir();
path = addPlaceHolder(dir,file,"{lucee-config-directory}");
if(!StringUtil.isEmpty(path)) return path;
// Web root
dir = config.getRootDirectory();
path = addPlaceHolder(dir,file,"{web-root-directory}");
if(!StringUtil.isEmpty(path)) return path;
return addPlaceHolder(file, defaultValue);
}
public static String parsePlaceHolder(String path, ServletContext sc, Map<String,String> labels) {
if(path==null) return null;
if(path.indexOf('{')!=-1){
if((path.indexOf("{web-context-label}"))!=-1){
String id=hash(sc);
String label=labels.get(id);
if(StringUtil.isEmpty(label)) label=id;
path=StringUtil.replace(path, "{web-context-label}", label, false);
}
}
return parsePlaceHolder(path, sc);
}
public static String parsePlaceHolder(String path, ServletContext sc) {
ResourceProvider frp = ResourcesImpl.getFileResourceProvider();
if(path==null) return null;
if(path.indexOf('{')!=-1){
if(StringUtil.startsWith(path,'{')){
// Web Root
if(path.startsWith("{web-root")) {
if(path.startsWith("}",9)) path=frp.getResource(ReqRspUtil.getRootPath(sc)).getRealResource(path.substring(10)).toString();
else if(path.startsWith("-dir}",9)) path=frp.getResource(ReqRspUtil.getRootPath(sc)).getRealResource(path.substring(14)).toString();
else if(path.startsWith("-directory}",9)) path=frp.getResource(ReqRspUtil.getRootPath(sc)).getRealResource(path.substring(20)).toString();
}
else path=SystemUtil.parsePlaceHolder(path);
}
if((path.indexOf("{web-context-hash}"))!=-1){
String id=hash(sc);
path=StringUtil.replace(path, "{web-context-hash}", id, false);
}
}
return path;
}
public static String hash(ServletContext sc) {
String id=null;
try {
id=MD5.getDigestAsString(ReqRspUtil.getRootPath(sc));
}
catch (IOException e) {}
return id;
}
public static Charset getCharset() {
return CharsetUtil.toCharset(charset);
}
public static CharSet getCharSet() {
return charset;
}
public static void setCharset(String charset) {
SystemUtil.charset = CharsetUtil.toCharSet(charset);
}
public static void setCharset(Charset charset) {
SystemUtil.charset = CharsetUtil.toCharSet(charset);
}
public static String getOSSpecificLineSeparator() {
return lineSeparator;
}
public static void sleep(int time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {}
}
public static void sleep(long time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {}
}
public static void join(Thread t) {
try {
t.join();
} catch (InterruptedException e) {}
}
/**
* locks the object (synchronized) before calling wait
* @param lock
* @param timeout
* @throws InterruptedException
*/
public static void wait(Object lock, long timeout) {
try {
synchronized (lock) {lock.wait(timeout);}
} catch (InterruptedException e) {}
}
/**
* locks the object (synchronized) before calling wait (no timeout)
* @param lock
* @throws InterruptedException
*/
public static void wait(Object lock) {
try {
synchronized (lock) {lock.wait();}
} catch (InterruptedException e) {}
}
/**
* locks the object (synchronized) before calling notify
* @param lock
* @param timeout
* @throws InterruptedException
*/
public static void notify(Object lock) {
synchronized (lock) {lock.notify();}
}
/**
* locks the object (synchronized) before calling notifyAll
* @param lock
* @param timeout
* @throws InterruptedException
*/
public static void notifyAll(Object lock) {
synchronized (lock) {lock.notifyAll();}
}
/**
* return the operating system architecture
* @return one of the following SystemUtil.ARCH_UNKNOW, SystemUtil.ARCH_32, SystemUtil.ARCH_64
*/
public static int getOSArch(){
if(osArch==-1) {
osArch = toIntArch(System.getProperty("os.arch.data.model"));
if(osArch==ARCH_UNKNOW)osArch = toIntArch(System.getProperty("os.arch"));
}
return osArch;
}
/**
* return the JRE (Java Runtime Engine) architecture, this can be different from the operating system architecture
* @return one of the following SystemUtil.ARCH_UNKNOW, SystemUtil.ARCH_32, SystemUtil.ARCH_64
*/
public static int getJREArch(){
if(jreArch==-1) {
jreArch = toIntArch(System.getProperty("sun.arch.data.model"));
if(jreArch==ARCH_UNKNOW)jreArch = toIntArch(System.getProperty("com.ibm.vm.bitmode"));
if(jreArch==ARCH_UNKNOW)jreArch = toIntArch(System.getProperty("java.vm.name"));
if(jreArch==ARCH_UNKNOW) {
int addrSize = getAddressSize();
if(addrSize==4) return ARCH_32;
if(addrSize==8) return ARCH_64;
}
}
return jreArch;
}
private static int toIntArch(String strArch){
if(!StringUtil.isEmpty(strArch)) {
if(strArch.indexOf("64")!=-1) return ARCH_64;
if(strArch.indexOf("32")!=-1) return ARCH_32;
if(strArch.indexOf("i386")!=-1) return ARCH_32;
if(strArch.indexOf("x86")!=-1) return ARCH_32;
}
return ARCH_UNKNOW;
}
public static int getAddressSize() {
try {
Class<?> unsafe = ClassUtil.loadClass("sun.misc.Unsafe",null);
if(unsafe==null) return 0;
Field unsafeField = unsafe.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Object obj = unsafeField.get(null);
Method addressSize = unsafe.getMethod("addressSize", new Class[0]);
Object res = addressSize.invoke(obj, new Object[0]);
return Caster.toIntValue(res,0);
}
catch(Throwable t){
ExceptionUtil.rethrowIfNecessary(t);
return 0;
}
}
/*private static MemoryUsage getPermGenSpaceSize() {
MemoryUsage mu = getPermGenSpaceSize(null);
if(mu!=null) return mu;
// create error message including info about available memory blocks
StringBuilder sb=new StringBuilder();
java.util.List<MemoryPoolMXBean> manager = ManagementFactory.getMemoryPoolMXBeans();
Iterator<MemoryPoolMXBean> it = manager.iterator();
MemoryPoolMXBean bean;
while(it.hasNext()){
bean = it.next();
if(sb.length()>0)sb.append(", ");
sb.append(bean.getName());
}
throw new RuntimeException("PermGen Space information not available, available Memory blocks are ["+sb+"]");
}*/
private static MemoryUsage getPermGenSpaceSize(MemoryUsage defaultValue) {
if(permGenSpaceBean!=null) return permGenSpaceBean.getUsage();
// create on the fly when the bean is not permanent
MemoryPoolMXBean tmp = getPermGenSpaceBean();
if(tmp!=null) return tmp.getUsage();
return defaultValue;
}
public static long getFreePermGenSpaceSize() {
MemoryUsage mu = getPermGenSpaceSize(null);
if(mu==null) return -1;
long max = mu.getMax();
long used = mu.getUsed();
if(max<0 || used<0) return -1;
return max-used;
}
public static int getPermGenFreeSpaceAsAPercentageOfAvailable() {
MemoryUsage mu = getPermGenSpaceSize(null);
if(mu == null) return -1;
long max = mu.getMax();
long used = mu.getUsed();
if( max < 0 || used < 0) return -1;
//return a value that equates to a percentage of available free memory
return 100 - ((int)(100 * (((double)used) / ((double)max))));
}
public static int getFreePermGenSpacePromille() {
MemoryUsage mu = getPermGenSpaceSize(null);
if(mu==null) return -1;
long max = mu.getMax();
long used = mu.getUsed();
if(max<0 || used<0) return -1;
return (int)(1000L-(1000L*used/max));
}
public static Query getMemoryUsageAsQuery(int type) throws DatabaseException {
java.util.List<MemoryPoolMXBean> manager = ManagementFactory.getMemoryPoolMXBeans();
Iterator<MemoryPoolMXBean> it = manager.iterator();
Query qry=new QueryImpl(new Collection.Key[]{
KeyConstants._name,
KeyConstants._type,
KeyConstants._used,
KeyConstants._max,
KeyConstants._init
},0,"memory");
int row=0;
MemoryPoolMXBean bean;
MemoryUsage usage;
MemoryType _type;
while(it.hasNext()){
bean = it.next();
usage = bean.getUsage();
_type = bean.getType();
if(type==MEMORY_TYPE_HEAP && _type!=MemoryType.HEAP)continue;
if(type==MEMORY_TYPE_NON_HEAP && _type!=MemoryType.NON_HEAP)continue;
row++;
qry.addRow();
qry.setAtEL(KeyConstants._name, row, bean.getName());
qry.setAtEL(KeyConstants._type, row, _type.name());
qry.setAtEL(KeyConstants._max, row, Caster.toDouble(usage.getMax()));
qry.setAtEL(KeyConstants._used, row, Caster.toDouble(usage.getUsed()));
qry.setAtEL(KeyConstants._init, row, Caster.toDouble(usage.getInit()));
}
return qry;
}
public static Struct getMemoryUsageAsStruct(int type) {
java.util.List<MemoryPoolMXBean> manager = ManagementFactory.getMemoryPoolMXBeans();
Iterator<MemoryPoolMXBean> it = manager.iterator();
MemoryPoolMXBean bean;
MemoryUsage usage;
MemoryType _type;
long used=0,max=0,init=0;
while(it.hasNext()){
bean = it.next();
usage = bean.getUsage();
_type = bean.getType();
if((type==MEMORY_TYPE_HEAP && _type==MemoryType.HEAP) || (type==MEMORY_TYPE_NON_HEAP && _type==MemoryType.NON_HEAP)){
used+=usage.getUsed();
max+=usage.getMax();
init+=usage.getInit();
}
}
Struct sct=new StructImpl();
sct.setEL(KeyConstants._used, Caster.toDouble(used));
sct.setEL(KeyConstants._max, Caster.toDouble(max));
sct.setEL(KeyConstants._init, Caster.toDouble(init));
sct.setEL(KeyImpl.init("available"), Caster.toDouble(max-used));
return sct;
}
public static Struct getMemoryUsageCompact(int type) {
java.util.List<MemoryPoolMXBean> manager = ManagementFactory.getMemoryPoolMXBeans();
Iterator<MemoryPoolMXBean> it = manager.iterator();
MemoryPoolMXBean bean;
MemoryUsage usage;
MemoryType _type;
Struct sct=new StructImpl();
while(it.hasNext()){
bean = it.next();
usage = bean.getUsage();
_type = bean.getType();
if(type==MEMORY_TYPE_HEAP && _type!=MemoryType.HEAP)continue;
if(type==MEMORY_TYPE_NON_HEAP && _type!=MemoryType.NON_HEAP)continue;
double d=((int)(100D/usage.getMax()*usage.getUsed()))/100D;
sct.setEL(KeyImpl.init(bean.getName()), Caster.toDouble(d));
}
return sct;
}
public static String getPropertyEL(String key) {
try{
String str = System.getProperty(key);
if(!StringUtil.isEmpty(str,true)) return str;
Iterator<Entry<Object, Object>> it = System.getProperties().entrySet().iterator();
Entry<Object, Object> e;
String n;
while(it.hasNext()){
e = it.next();
n=(String) e.getKey();
if(key.equalsIgnoreCase(n)) return (String) e.getValue();
}
}
catch(Throwable t){ExceptionUtil.rethrowIfNecessary(t);}
return null;
}
public static long microTime() {
return System.nanoTime()/1000L;
}
public static TemplateLine getCurrentContext() {
StackTraceElement[] traces = Thread.currentThread().getStackTrace();
int line=0;
String template;
StackTraceElement trace=null;
for(int i=0;i<traces.length;i++) {
trace=traces[i];
template=trace.getFileName();
if(trace.getLineNumber()<=0 || template==null || ResourceUtil.getExtension(template,"").equals("java")) continue;
line=trace.getLineNumber();
return new TemplateLine(template,line);
}
return null;
}
public static class TemplateLine implements Serializable {
private static final long serialVersionUID = 6610978291828389799L;
public final String template;
public final int line;
public TemplateLine(String template, int line) {
this.template=template;
this.line=line;
}
@Override
public String toString(){
return template+":"+line;
}
}
public static long getFreeBytes() throws ApplicationException {
return physical().getFreeBytes();
}
public static long getTotalBytes() throws ApplicationException {
return physical().getTotalBytes();
}
public static double getCpuUsage(long time) throws ApplicationException {
if(time<1) throw new ApplicationException("time has to be bigger than 0");
if(jsm==null) jsm=new JavaSysMon();
CpuTimes cput = jsm.cpuTimes();
if(cput==null) throw new ApplicationException("CPU information are not available for this OS");
CpuTimes previous = new CpuTimes(cput.getUserMillis(),cput.getSystemMillis(),cput.getIdleMillis());
sleep(time);
return jsm.cpuTimes().getCpuUsage(previous)*100D;
}
private synchronized static MemoryStats physical() throws ApplicationException {
if(jsm==null) jsm=new JavaSysMon();
MemoryStats p = jsm.physical();
if(p==null) throw new ApplicationException("Memory information are not available for this OS");
return p;
}
public static void setPrintWriter(int type,PrintWriter pw) {
printWriter[type]=pw;
}
public static PrintWriter getPrintWriter(int type) {
if(printWriter[type]==null) {
if(type==OUT) printWriter[OUT]=PRINTWRITER_OUT;
else printWriter[ERR]=PRINTWRITER_ERR;
}
return printWriter[type];
}
public static boolean isCLICall() {
if(isCLI==null){
isCLI=Caster.toBoolean(System.getProperty("lucee.cli.call"),Boolean.FALSE);
}
return isCLI.booleanValue();
}
public static double getLoaderVersion() {
// this is done via reflection to make it work in older version, where the class lucee.loader.Version does not exist
if(loaderVersion==0D) {
loaderVersion=4D;
Class<?> cVersion = ClassUtil.loadClass(getLoaderClassLoader(),"lucee.loader.Version",null);
if(cVersion!=null) {
try {
Field f = cVersion.getField("VERSION");
loaderVersion=f.getDouble(null);
}
catch(Throwable t) {ExceptionUtil.rethrowIfNecessary(t);}
}
}
return loaderVersion;
}
public static String getMacAddress(String defaultValue) {
if(!hasMacAddress) {
try{
InetAddress ip = InetAddress.getLocalHost();
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
if(network==null) {
hasMacAddress=true;
return null;
}
byte[] mac = network.getHardwareAddress();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < mac.length; i++) {
sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));
}
macAddress= sb.toString();
}
catch(Throwable t){ExceptionUtil.rethrowIfNecessary(t);}
hasMacAddress=true;
}
return macAddress;
}
public static URL getResource(Bundle bundle, String path) {
String pws,pns;
if(path.startsWith("/")) {
pws=path;
pns=path.substring(1);
}
else {
pws="/"+path;
pns=path;
}
URL url=null;
if(bundle!=null) {
try {
url = bundle.getEntry(pns);
}
catch(Throwable t) {ExceptionUtil.rethrowIfNecessary(t);}
}
// core class loader
if(url==null) {
Class<?> clazz = PageSourceImpl.class;
ClassLoader cl = clazz.getClassLoader();
url=cl.getResource(pns);
if(url==null) {
url=cl.getResource(pws);
}
}
return url;
}
/**
* returns a system setting by either a Java property name or a System environment variable
*
* @param name - either a lowercased Java property name (e.g. lucee.controller.disabled) or an UPPERCASED Environment variable name ((e.g. LUCEE_CONTROLLER_DISABLED))
* @param defaultValue - value to return if the neither the property nor the environment setting was found
* @return - the value of the property referenced by propOrEnv or the defaultValue if not found
*/
public static String getSystemPropOrEnvVar(String name, String defaultValue) {
// env
String value=System.getenv(name);
if(!StringUtil.isEmpty(value)) return value;
// prop
value=System.getProperty(name);
if(!StringUtil.isEmpty(value)) return value;
// env 2
name=name.replace('.', '_').toUpperCase();
value=System.getenv(name);
if(!StringUtil.isEmpty(value)) return value;
return defaultValue;
}
public static void addLibraryPathIfNoExist(Resource res,Log log){
String existing = System.getProperty("java.library.path");
if(StringUtil.isEmpty(existing)) {
if(log!=null)log.info("Instrumentation","add "+res.getAbsolutePath()+" to library path");
System.setProperty("java.library.path",res.getAbsolutePath());
}
else if(existing.indexOf(res.getAbsolutePath())!=-1){
return;
}
else {
if(log!=null)log.info("Instrumentation","add "+res.getAbsolutePath()+" to library path");
System.setProperty("java.library.path",res.getAbsolutePath() + (isWindows()?";":":") + existing);
}
// Important: java.library.path is cached
// We will be using reflection to clear the cache
try{
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
fieldSysPath.setAccessible(true);
fieldSysPath.set(null, null);
}
catch(Throwable t){ExceptionUtil.rethrowIfNecessary(t);}
}
@Deprecated
public static void stop(Thread thread) {
if(thread.isAlive()){
thread.stop();
/*try{
thread.stop(new StopException(thread));
}
catch(UnsupportedOperationException uoe){// Java 8 does not support Thread.stop(Throwable)
thread.stop();
}*/
}
}
public static void stop(PageContext pc, Log log, boolean async) {
if(async)new StopThread(pc,log).start();
else new StopThread(pc,log).run();
}
public static String getLocalHostName() {
String result = System.getenv(isWindows() ? "COMPUTERNAME" : "HOSTNAME");
if (!StringUtil.isEmpty(result))
return result;
try {
return InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException ex) {
return "";
}
}
public static InputStream getResourceAsStream(Bundle bundle, String path) {
// check the bundle for the resource
InputStream is;
if(bundle!=null) {
try {
is = bundle.getEntry(path).openStream();
if(is!=null) return is;
}catch(Throwable t) {ExceptionUtil.rethrowIfNecessary(t);}
}
// try from core classloader
ClassLoader cl = PageSourceImpl.class.getClassLoader();
try{
is = cl.getResourceAsStream(path);
if(is!=null) return is;
}catch(Throwable t) {ExceptionUtil.rethrowIfNecessary(t);}
// try from loader classloader
cl = PageSource.class.getClassLoader();
try{
is = cl.getResourceAsStream(path);
if(is!=null) return is;
}catch(Throwable t) {ExceptionUtil.rethrowIfNecessary(t);}
// try from loader classloader
cl = ClassLoader.getSystemClassLoader();
try{
is = cl.getResourceAsStream(path);
if(is!=null) return is;
}catch(Throwable t) {ExceptionUtil.rethrowIfNecessary(t);}
return null;
}
/**
* @return returns a class stack trace
*/
public static Class<?>[] getClassContext() {
final Ref ref=new Ref();
new SecurityManager() {
{
ref.context = getClassContext();
}
};
Class<?>[] context= new Class[ref.context.length-2];
System.arraycopy(ref.context, 2,context, 0, ref.context.length-2);
return context;
}
/**
*
* @return the class calling me and the first class not in bootdelegation if the the is in bootdelegation
*/
public static Caller getCallerClass() {
final Ref ref=new Ref();
new SecurityManager() {
{
ref.context = getClassContext();
}
};
Caller rtn=new Caller();
// element at position 2 is the caller
Class<?> caller=ref.context[2];
RefInteger index=new RefIntegerImpl(3);
Class<?> clazz=_getCallerClass(ref.context,caller,index,true,true);
// analyze the first result
if(clazz==null) return rtn;
if(isFromBundle(clazz)) {
rtn.fromBundle=clazz;
return rtn;
}
if(!OSGiUtil.isClassInBootelegation(clazz.getName())) {
rtn.fromSystem=clazz;
}
else {
rtn.fromBootDelegation=clazz;
}
clazz=null;
if(rtn.fromBootDelegation!=null) {
clazz=_getCallerClass(ref.context,caller,index,false,true);
if(clazz==null) return rtn;
if(isFromBundle(clazz)) {
rtn.fromBundle=clazz;
return rtn;
}
else rtn.fromSystem=clazz;
}
clazz=_getCallerClass(ref.context,caller,index,false,false);
if(clazz==null) return rtn;
rtn.fromBundle=clazz;
return rtn;
}
private static Class<?> _getCallerClass(Class<?>[] context, Class<?> caller, RefInteger index, boolean acceptBootDelegation, boolean acceptSystem) {
Class<?> callerCaller;
do{
callerCaller=context[index.toInt()];
index.plus(1);
if(callerCaller==caller || _isSystem(callerCaller)) {
callerCaller=null;
}
if(callerCaller!=null && !acceptSystem && !isFromBundle(callerCaller)) {
callerCaller=null;
}
else if(callerCaller!=null && !acceptBootDelegation && OSGiUtil.isClassInBootelegation(callerCaller.getName())) {
callerCaller=null;
}
}
while(callerCaller==null && index.toInt()<context.length);
return callerCaller;
}
public static class Caller {
public Class<?> fromBootDelegation;
public Class<?> fromSystem;
public Class<?> fromBundle;
public String toString(){
return "fromBootDelegation:"+fromBootDelegation+";fromSystem:"+fromSystem+";fromBundle:"+fromBundle;
}
public boolean isEmpty() {
return fromBootDelegation==null && fromBundle==null && fromSystem==null;
}
public Class<?> fromClasspath() {
if(fromSystem!=null) {
if(fromSystem.getClassLoader()!=null)
return fromSystem;
if(fromBootDelegation!=null && fromBootDelegation.getClassLoader()!=null) return fromBootDelegation;
return fromSystem;
}
return fromBootDelegation;
}
}
private static boolean isFromBundle(Class<?> clazz) {
if(clazz==null) return false;
if(!(clazz.getClassLoader() instanceof BundleReference))
return false;
BundleReference br=(BundleReference)clazz.getClassLoader();
return !OSGiUtil.isFrameworkBundle(br.getBundle());
}
private static boolean _isSystem(Class<?> clazz) {
if(clazz.getName()=="java.lang.Class") return true; // Class.forName(className)
if(clazz.getName().startsWith("com.sun.beans.finder.")) return true;
if(clazz.getName().startsWith("java.beans.")) return true;
if(clazz.getName().startsWith("java.util.ServiceLoader")) return true;
return false;
}
private static Map<String,Integer> logs=new ConcurrentHashMap<String, Integer>();
public static void logUsage() {
String st=ExceptionUtil.getStacktrace(new Throwable(), false);
Integer res = logs.get(st);
if(res==null) res=1;
else res=res.intValue()+1;
logs.put(st, res);
}
public static Map<String, Integer> getLogUsage() {
return logs;
}
}
class Ref {
public Class<?>[] context;
}
class StopThread extends Thread {
private final PageContext pc;
private final Log log;
public StopThread(PageContext pc, Log log) {
this.pc=pc;
this.log=log;
}
public void run(){
PageContextImpl pci=(PageContextImpl) pc;
Thread thread = pc.getThread();
if(thread==null) return;
if(thread.isAlive()) {
pci.setTimeoutStackTrace();
thread.stop();
}
}
}