/*
* JBoss, Home of Professional Open Source.
* Copyright 2014 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.modules;
import java.io.File;
import java.net.URI;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Locale;
/**
* A base class for resource loaders which can load native libraries.
*
* @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
*/
public class NativeLibraryResourceLoader extends AbstractResourceLoader {
/**
* Separate class for native platform ID which is only loaded when native libs are loaded.
*/
static class Identification {
static final String OS_ID;
static final String CPU_ID;
static final String ARCH_NAME;
static final String[] NATIVE_SEARCH_PATHS;
static {
final Object[] strings = AccessController.doPrivileged(new PrivilegedAction<Object[]>() {
public Object[] run() {
// First, identify the operating system.
boolean knownOs = true;
String osName;
// let the user override it.
osName = System.getProperty("jboss.modules.os-name");
if (osName == null) {
String sysOs = System.getProperty("os.name");
if (sysOs == null) {
osName = "unknown";
knownOs = false;
} else {
sysOs = sysOs.toUpperCase(Locale.US);
if (sysOs.startsWith("LINUX")) {
osName = "linux";
} else if (sysOs.startsWith("MAC OS")) {
osName = "macosx";
} else if (sysOs.startsWith("WINDOWS")) {
osName = "win";
} else if (sysOs.startsWith("OS/2")) {
osName = "os2";
} else if (sysOs.startsWith("SOLARIS") || sysOs.startsWith("SUNOS")) {
osName = "solaris";
} else if (sysOs.startsWith("MPE/IX")) {
osName = "mpeix";
} else if (sysOs.startsWith("HP-UX")) {
osName = "hpux";
} else if (sysOs.startsWith("AIX")) {
osName = "aix";
} else if (sysOs.startsWith("OS/390")) {
osName = "os390";
} else if (sysOs.startsWith("OS/400")) {
osName = "os400";
} else if (sysOs.startsWith("FREEBSD")) {
osName = "freebsd";
} else if (sysOs.startsWith("OPENBSD")) {
osName = "openbsd";
} else if (sysOs.startsWith("NETBSD")) {
osName = "netbsd";
} else if (sysOs.startsWith("IRIX")) {
osName = "irix";
} else if (sysOs.startsWith("DIGITAL UNIX")) {
osName = "digitalunix";
} else if (sysOs.startsWith("OSF1")) {
osName = "osf1";
} else if (sysOs.startsWith("OPENVMS")) {
osName = "openvms";
} else if (sysOs.startsWith("IOS")) {
osName = "iOS";
} else {
osName = "unknown";
knownOs = false;
}
}
}
// Next, our CPU ID and its compatible variants.
boolean knownCpu = true;
ArrayList<String> cpuNames = new ArrayList<>();
String cpuName = System.getProperty("jboss.modules.cpu-name");
if (cpuName == null) {
String sysArch = System.getProperty("os.arch");
if (sysArch == null) {
cpuName = "unknown";
knownCpu = false;
} else {
boolean hasEndian = false;
boolean hasHardFloatABI = false;
sysArch = sysArch.toUpperCase(Locale.US);
if (sysArch.startsWith("SPARCV9") || sysArch.startsWith("SPARC64")) {
cpuName = "sparcv9";
} else if (sysArch.startsWith("SPARC")) {
cpuName = "sparc";
} else if (sysArch.startsWith("X86_64") || sysArch.startsWith("AMD64")) {
cpuName = "x86_64";
} else if (sysArch.startsWith("I386") || sysArch.startsWith("I486") || sysArch.startsWith("I586") || sysArch.startsWith("I686") || sysArch.startsWith("X86") || sysArch.contains("IA32")) {
cpuName = "i686";
} else if (sysArch.startsWith("X32")) {
cpuName = "x32";
} else if (sysArch.startsWith("PPC64")) {
cpuName = "ppc64";
} else if (sysArch.startsWith("PPC") || sysArch.startsWith("POWER")) {
cpuName = "ppc";
} else if (sysArch.startsWith("ARMV7A") || sysArch.contains("AARCH32")) {
hasEndian = true;
hasHardFloatABI = true;
cpuName = "armv7a";
} else if (sysArch.startsWith("AARCH64") || sysArch.startsWith("ARM64") || sysArch.startsWith("ARMV8") || sysArch.startsWith("PXA9") || sysArch.startsWith("PXA10")) {
hasEndian = true;
cpuName = "aarch64";
} else if (sysArch.startsWith("PXA27")) {
hasEndian = true;
cpuName = "armv5t-iwmmx";
} else if (sysArch.startsWith("PXA3")) {
hasEndian = true;
cpuName = "armv5t-iwmmx2";
} else if (sysArch.startsWith("ARMV4T") || sysArch.startsWith("EP93")) {
hasEndian = true;
cpuName = "armv4t";
} else if (sysArch.startsWith("ARMV4") || sysArch.startsWith("EP73")) {
hasEndian = true;
cpuName = "armv4";
} else if (sysArch.startsWith("ARMV5T") || sysArch.startsWith("PXA") || sysArch.startsWith("IXC") || sysArch.startsWith("IOP") || sysArch.startsWith("IXP") || sysArch.startsWith("CE")) {
hasEndian = true;
String isaList = System.getProperty("sun.arch.isalist");
if (isaList != null) {
if (isaList.toUpperCase(Locale.US).contains("MMX2")) {
cpuName = "armv5t-iwmmx2";
} else if (isaList.toUpperCase(Locale.US).contains("MMX")) {
cpuName = "armv5t-iwmmx";
} else {
cpuName = "armv5t";
}
} else {
cpuName = "armv5t";
}
} else if (sysArch.startsWith("ARMV5")) {
hasEndian = true;
cpuName = "armv5";
} else if (sysArch.startsWith("ARMV6")) {
hasEndian = true;
hasHardFloatABI = true;
cpuName = "armv6";
} else if (sysArch.startsWith("PA_RISC2.0W")) {
cpuName = "parisc64";
} else if (sysArch.startsWith("PA_RISC") || sysArch.startsWith("PA-RISC")) {
cpuName = "parisc";
} else if (sysArch.startsWith("IA64")) {
// HP-UX reports IA64W for 64-bit Itanium and IA64N when running
// in 32-bit mode.
cpuName = sysArch.toLowerCase(Locale.US);
} else if (sysArch.startsWith("ALPHA")) {
cpuName = "alpha";
} else if (sysArch.startsWith("MIPS")) {
cpuName = "mips";
} else {
knownCpu = false;
cpuName = "unknown";
}
boolean be = false;
boolean hf = false;
if (knownCpu && hasEndian && "big".equals(System.getProperty("sun.cpu.endian", "little"))) {
be = true;
}
if (knownCpu && hasHardFloatABI) {
String archAbi = System.getProperty("sun.arch.abi");
if (archAbi != null) {
if (archAbi.toUpperCase(Locale.US).contains("HF")) {
hf = true;
}
} else {
String libPath = System.getProperty("java.library.path");
if (libPath != null && libPath.toUpperCase(Locale.US).contains("GNUEABIHF")) {
hf = true;
}
}
if (hf) cpuName += "-hf";
}
if (knownCpu) {
switch (cpuName) {
case "i686": cpuNames.add("i686");
case "i586": cpuNames.add("i586");
case "i486": cpuNames.add("i486");
case "i386": cpuNames.add("i386");
break;
case "armv7a": cpuNames.add("armv7a"); if (hf) break;
case "armv6": cpuNames.add("armv6"); if (hf) break;
case "armv5t": cpuNames.add("armv5t");
case "armv5": cpuNames.add("armv5");
case "armv4t": cpuNames.add("armv4t");
case "armv4": cpuNames.add("armv4");
break;
case "armv5t-iwmmx2": cpuNames.add("armv5t-iwmmx2");
case "armv5t-iwmmx": cpuNames.add("armv5t-iwmmx");
cpuNames.add("armv5t");
cpuNames.add("armv5");
cpuNames.add("armv4t");
cpuNames.add("armv4");
break;
default: cpuNames.add(cpuName);
break;
}
if (hf || be) for (int i = 0; i < cpuNames.size(); i++) {
String name = cpuNames.get(i);
if (be) name += "-be";
if (hf) name += "-hf";
cpuNames.set(i, name);
}
cpuName = cpuNames.get(0);
}
}
} else {
cpuNames.add(cpuName);
}
// Finally, search paths.
final int cpuCount = cpuNames.size();
String[] searchPaths = new String[cpuCount];
if (knownOs && knownCpu) {
for (int i = 0; i < cpuCount; i++) {
final String name = cpuNames.get(i);
searchPaths[i] = osName + "-" + name;
}
} else {
searchPaths = new String[0];
}
return new Object[] {
osName,
cpuName,
osName + "-" + cpuName,
searchPaths
};
}
});
OS_ID = strings[0].toString();
CPU_ID = strings[1].toString();
ARCH_NAME = strings[2].toString();
NATIVE_SEARCH_PATHS = (String[]) strings[3];
}
}
/**
* The filesystem root of the resource loader.
*/
private final File root;
/**
* Construct a new instance.
*
* @param root the filesystem root of the resource loader
*/
public NativeLibraryResourceLoader(final File root) {
this.root = root;
}
/** {@inheritDoc} */
public String getLibrary(final String name) {
final String mappedName = System.mapLibraryName(name);
final File root = this.root;
File testFile;
for (String path : Identification.NATIVE_SEARCH_PATHS) {
testFile = new File(new File(root, path), mappedName);
if (testFile.exists()) {
return testFile.getAbsolutePath();
}
}
return null;
}
public URI getLocation() {
return root.toURI();
}
/**
* Get the filesystem root of the resource loader.
*
* @return the filesystem root of the resource loader
*/
public File getRoot() {
return root;
}
/**
* Get the detected architecture name for this platform.
*
* @return the architecture name
*/
public static String getArchName() {
return Identification.ARCH_NAME;
}
}