PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/com/kenai/jaffl/Platform.java

http://github.com/wmeissner/jaffl
Java | 454 lines | 282 code | 53 blank | 119 comment | 58 complexity | f7d23199c83fe176c22734ee7893329d MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0
  1. package com.kenai.jaffl;
  2. import java.io.File;
  3. import java.io.FilenameFilter;
  4. import java.util.Arrays;
  5. import java.util.LinkedList;
  6. import java.util.List;
  7. import java.util.regex.Pattern;
  8. public abstract class Platform {
  9. private final OS os;
  10. private final CPU cpu;
  11. private final int addressSize;
  12. private final int longSize;
  13. protected final Pattern libPattern;
  14. private static final class SingletonHolder {
  15. static final Platform PLATFORM = determinePlatform();
  16. }
  17. /**
  18. * The common names of supported operating systems.
  19. */
  20. public enum OS {
  21. /*
  22. * Note The names of the enum values are used in other parts of the
  23. * code to determine where to find the native stub library. Do not rename.
  24. */
  25. /** MacOSX */
  26. DARWIN,
  27. /** FreeBSD */
  28. FREEBSD,
  29. /** NetBSD */
  30. NETBSD,
  31. /** OpenBSD */
  32. OPENBSD,
  33. /** Linux */
  34. LINUX,
  35. /** Solaris (and OpenSolaris) */
  36. SOLARIS,
  37. /** The evil borg operating system */
  38. WINDOWS,
  39. /** IBM AIX */
  40. AIX,
  41. /** IBM zOS **/
  42. ZLINUX,
  43. /** No idea what the operating system is */
  44. UNKNOWN;
  45. @Override
  46. public String toString() {
  47. return name().toLowerCase();
  48. }
  49. }
  50. /**
  51. * The supported CPU architectures.
  52. */
  53. public enum CPU {
  54. /*
  55. * <b>Note</b> The names of the enum values are used in other parts of the
  56. * code to determine where to find the native stub library. Do NOT rename.
  57. */
  58. /** 32 bit legacy Intel */
  59. I386,
  60. /** 64 bit AMD (aka EM64T/X64) */
  61. X86_64,
  62. /** 32 bit Power PC */
  63. PPC,
  64. /** 64 bit Power PC */
  65. PPC64,
  66. /** 32 bit Sun sparc */
  67. SPARC,
  68. /** 64 bit Sun sparc */
  69. SPARCV9,
  70. /** IBM zSeries S/390 */
  71. S390X,
  72. /** 32 bit MIPS (used by nestedvm) */
  73. MIPS32,
  74. /**
  75. * Unknown CPU architecture. A best effort will be made to infer architecture
  76. * specific values such as address and long size.
  77. */
  78. UNKNOWN;
  79. /**
  80. * Returns a {@code String} object representing this {@code CPU} object.
  81. *
  82. * @return the name of the cpu architecture as a lower case {@code String}.
  83. */
  84. @Override
  85. public String toString() {
  86. return name().toLowerCase();
  87. }
  88. }
  89. /**
  90. * Determines the operating system jffi is running on
  91. *
  92. * @return An member of the <tt>OS</tt> enum.
  93. */
  94. private static final OS determineOS() {
  95. String osName = System.getProperty("os.name").split(" ")[0].toLowerCase();
  96. if (osName.startsWith("mac") || osName.startsWith("darwin")) {
  97. return OS.DARWIN;
  98. } else if (osName.startsWith("linux")) {
  99. return OS.LINUX;
  100. } else if (osName.startsWith("sunos") || osName.startsWith("solaris")) {
  101. return OS.SOLARIS;
  102. } else if (osName.startsWith("aix")) {
  103. return OS.AIX;
  104. } else if (osName.startsWith("openbsd")) {
  105. return OS.OPENBSD;
  106. } else if (osName.startsWith("freebsd")) {
  107. return OS.FREEBSD;
  108. } else if (osName.startsWith("windows")) {
  109. return OS.WINDOWS;
  110. } else {
  111. return OS.UNKNOWN;
  112. }
  113. }
  114. /**
  115. * Determines the <tt>Platform</tt> that best describes the <tt>OS</tt>
  116. *
  117. * @param os The operating system.
  118. * @return An instance of <tt>Platform</tt>
  119. */
  120. private static final Platform determinePlatform(OS os) {
  121. switch (os) {
  122. case DARWIN:
  123. return new Darwin();
  124. case LINUX:
  125. return new Linux();
  126. case WINDOWS:
  127. return new Windows();
  128. case UNKNOWN:
  129. return new Unsupported(os);
  130. default:
  131. return new Default(os);
  132. }
  133. }
  134. private static final Platform determinePlatform() {
  135. String providerName = System.getProperty("jaffl.provider");
  136. try {
  137. Class c = Class.forName(providerName + "$Platform");
  138. return (Platform) c.newInstance();
  139. } catch (ClassNotFoundException ex) {
  140. return determinePlatform(determineOS());
  141. } catch (IllegalAccessException ex) {
  142. throw new ExceptionInInitializerError(ex);
  143. } catch (InstantiationException ex) {
  144. throw new ExceptionInInitializerError(ex);
  145. }
  146. }
  147. private static final CPU determineCPU() {
  148. String archString = System.getProperty("os.arch").toLowerCase();
  149. if ("x86".equals(archString) || "i386".equals(archString) || "i86pc".equals(archString)) {
  150. return CPU.I386;
  151. } else if ("x86_64".equals(archString) || "amd64".equals(archString)) {
  152. return CPU.X86_64;
  153. } else if ("ppc".equals(archString) || "powerpc".equals(archString)) {
  154. return CPU.PPC;
  155. }
  156. // Try to find by lookup up in the CPU list
  157. try {
  158. return CPU.valueOf(archString.toUpperCase());
  159. } catch (IllegalArgumentException ex) {
  160. return CPU.UNKNOWN;
  161. }
  162. }
  163. public Platform(OS os, CPU cpu, int addressSize, int longSize, String libPattern) {
  164. this.os = os;
  165. this.cpu = cpu;
  166. this.addressSize = addressSize;
  167. this.longSize = longSize;
  168. this.libPattern = Pattern.compile(libPattern);
  169. }
  170. private Platform(OS os) {
  171. this.os = os;
  172. this.cpu = determineCPU();
  173. String libpattern = null;
  174. switch (os) {
  175. case WINDOWS:
  176. libpattern = ".*\\.dll$";
  177. break;
  178. case DARWIN:
  179. libpattern = "lib.*\\.(dylib|jnilib)$";
  180. break;
  181. default:
  182. libpattern = "lib.*\\.so.*$";
  183. break;
  184. }
  185. libPattern = Pattern.compile(libpattern);
  186. this.addressSize = calculateAddressSize(cpu);
  187. this.longSize = os == OS.WINDOWS ? 32 : addressSize;
  188. }
  189. private static final int calculateAddressSize(CPU cpu) {
  190. int dataModel = Integer.getInteger("sun.arch.data.model");
  191. if (dataModel != 32 && dataModel != 64) {
  192. switch (cpu) {
  193. case I386:
  194. case PPC:
  195. case SPARC:
  196. dataModel = 32;
  197. break;
  198. case X86_64:
  199. case PPC64:
  200. case SPARCV9:
  201. case S390X:
  202. dataModel = 64;
  203. break;
  204. default:
  205. throw new ExceptionInInitializerError("Cannot determine cpu address size");
  206. }
  207. }
  208. return dataModel;
  209. }
  210. /**
  211. * Gets the native <tt>Platform</tt>
  212. *
  213. * @return The current platform.
  214. */
  215. public static final Platform getNativePlatform() {
  216. return SingletonHolder.PLATFORM;
  217. }
  218. @Deprecated
  219. public static final Platform getPlatform() {
  220. return SingletonHolder.PLATFORM;
  221. }
  222. /**
  223. * Gets the current Operating System.
  224. *
  225. * @return A <tt>OS</tt> value representing the current Operating System.
  226. */
  227. public final OS getOS() {
  228. return os;
  229. }
  230. /**
  231. * Gets the current processor architecture the JVM is running on.
  232. *
  233. * @return A <tt>CPU</tt> value representing the current processor architecture.
  234. */
  235. public final CPU getCPU() {
  236. return cpu;
  237. }
  238. public final boolean isBSD() {
  239. return os == OS.FREEBSD || os == os.OPENBSD || os == OS.NETBSD || os == OS.DARWIN;
  240. }
  241. public final boolean isUnix() {
  242. return os != OS.WINDOWS;
  243. }
  244. /**
  245. * Gets the size of a C 'long' on the native platform.
  246. *
  247. * @return the size of a long in bits
  248. * @deprecated Use {@link Runtime#longSize()} instead.
  249. */
  250. public final int longSize() {
  251. return longSize;
  252. }
  253. /**
  254. * Gets the size of a C address/pointer on the native platform.
  255. *
  256. * @return the size of a pointer in bits
  257. * @deprecated Use {@link Runtime#addressSize()} instead.
  258. */
  259. public final int addressSize() {
  260. return addressSize;
  261. }
  262. /**
  263. * Gets the name of this <tt>Platform</tt>.
  264. *
  265. * @return The name of this platform.
  266. */
  267. public String getName() {
  268. return cpu + "-" + os;
  269. }
  270. /**
  271. * Maps from a generic library name (e.g. "c") to the platform specific library name.
  272. *
  273. * @param libName The library name to map
  274. * @return The mapped library name.
  275. */
  276. public String mapLibraryName(String libName) {
  277. //
  278. // A specific version was requested - use as is for search
  279. //
  280. if (libPattern.matcher(libName).find()) {
  281. return libName;
  282. }
  283. return System.mapLibraryName(libName);
  284. }
  285. /**
  286. * Searches through a list of directories for a native library.
  287. *
  288. * @param libName the base name (e.g. "c") of the library to locate
  289. * @param libraryPath the list of directories to search
  290. * @return the path of the library
  291. */
  292. public String locateLibrary(String libName, List<String> libraryPath) {
  293. String mappedName = mapLibraryName(libName);
  294. for (String path : libraryPath) {
  295. File libFile = new File(path, mappedName);
  296. if (libFile.exists()) {
  297. return libFile.getAbsolutePath();
  298. }
  299. }
  300. // Default to letting the system search for it
  301. return mappedName;
  302. }
  303. private static class Supported extends Platform {
  304. public Supported(OS os) {
  305. super(os);
  306. }
  307. }
  308. private static class Unsupported extends Platform {
  309. public Unsupported(OS os) {
  310. super(os);
  311. }
  312. }
  313. private static final class Default extends Supported {
  314. public Default(OS os) {
  315. super(os);
  316. }
  317. }
  318. /**
  319. * A {@link Platform} subclass representing the MacOS system.
  320. */
  321. private static final class Darwin extends Supported {
  322. public Darwin() {
  323. super(OS.DARWIN);
  324. }
  325. @Override
  326. public String mapLibraryName(String libName) {
  327. //
  328. // A specific version was requested - use as is for search
  329. //
  330. if (libPattern.matcher(libName).find()) {
  331. return libName;
  332. }
  333. return "lib" + libName + ".dylib";
  334. }
  335. @Override
  336. public String getName() {
  337. return "Darwin";
  338. }
  339. }
  340. /**
  341. * A {@link Platform} subclass representing the Linux operating system.
  342. */
  343. private static final class Linux extends Supported {
  344. public Linux() {
  345. super(OS.LINUX);
  346. }
  347. @Override
  348. public String locateLibrary(final String libName, List<String> libraryPath) {
  349. FilenameFilter filter = new FilenameFilter() {
  350. Pattern p = Pattern.compile("lib" + libName + "\\.so\\.[0-9]+$");
  351. String exact = "lib" + libName + ".so";
  352. public boolean accept(File dir, String name) {
  353. return p.matcher(name).matches() || exact.equals(name);
  354. }
  355. };
  356. List<File> matches = new LinkedList<File>();
  357. for (String path : libraryPath) {
  358. File[] files = new File(path).listFiles(filter);
  359. if (files != null && files.length > 0) {
  360. matches.addAll(Arrays.asList(files));
  361. }
  362. }
  363. //
  364. // Search through the results and return the highest numbered version
  365. // i.e. libc.so.6 is preferred over libc.so.5
  366. //
  367. int version = 0;
  368. String bestMatch = null;
  369. for (File file : matches) {
  370. String path = file.getAbsolutePath();
  371. if (bestMatch == null && path.endsWith(".so")) {
  372. bestMatch = path;
  373. version = 0;
  374. } else {
  375. String num = path.substring(path.lastIndexOf(".so.") + 4);
  376. try {
  377. if (Integer.parseInt(num) >= version) {
  378. bestMatch = path;
  379. }
  380. } catch (NumberFormatException e) {
  381. } // Just skip if not a number
  382. }
  383. }
  384. return bestMatch != null ? bestMatch : mapLibraryName(libName);
  385. }
  386. @Override
  387. public String mapLibraryName(String libName) {
  388. // Older JDK on linux map 'c' to 'libc.so' which doesn't work
  389. return "c".equals(libName) || "libc.so".equals(libName)
  390. ? "libc.so.6" : super.mapLibraryName(libName);
  391. }
  392. }
  393. /**
  394. * A {@link Platform} subclass representing the Windows system.
  395. */
  396. private static class Windows extends Supported {
  397. public Windows() {
  398. super(OS.WINDOWS);
  399. }
  400. }
  401. }