You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ag...@apache.org on 2017/11/29 10:28:52 UTC
[11/12] ignite git commit: IGNITE-7013 .NET: macOS support added
IGNITE-7013 .NET: macOS support added
This closes #3091
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/bf432ef4
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/bf432ef4
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/bf432ef4
Branch: refs/heads/ignite-7016
Commit: bf432ef44d039cb106ccb3c97aa473540899c82d
Parents: f1b47ed
Author: Pavel Tupitsyn <pt...@apache.org>
Authored: Tue Nov 28 18:32:16 2017 +0300
Committer: Alexey Goncharuk <al...@gmail.com>
Committed: Wed Nov 29 13:28:34 2017 +0300
----------------------------------------------------------------------
.../Common/TestLogger.cs | 74 ++++
.../Common/TestUtils.DotNetCore.cs | 46 ++-
.../Client/ClientConnectionTest.cs | 4 +-
.../Log/CustomLoggerTest.cs | 7 -
.../TestUtils.Common.cs | 3 -
.../Apache.Ignite.Core.csproj | 5 +-
.../Apache.Ignite.Core/IgniteConfiguration.cs | 7 +-
.../dotnet/Apache.Ignite.Core/Ignition.cs | 2 +-
.../Impl/Client/ClientSocket.cs | 12 +-
.../Apache.Ignite.Core/Impl/IgniteManager.cs | 8 +
.../Apache.Ignite.Core/Impl/IgniteUtils.cs | 242 -----------
.../dotnet/Apache.Ignite.Core/Impl/Shell.cs | 2 +
.../Impl/Unmanaged/DllLoader.cs | 176 --------
.../Impl/Unmanaged/Jni/DllLoader.cs | 210 ++++++++++
.../Impl/Unmanaged/Jni/Jvm.cs | 80 +---
.../Impl/Unmanaged/Jni/JvmDll.cs | 414 +++++++++++++++++++
.../Impl/Unmanaged/Jni/JvmInitArgs.cs | 33 ++
.../Impl/Unmanaged/Jni/JvmOption.cs | 34 ++
.../Apache.Ignite.Core/Impl/Unmanaged/Os.cs | 6 +
modules/platforms/dotnet/Apache.Ignite.ndproj | 2 +-
20 files changed, 837 insertions(+), 530 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Common/TestLogger.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Common/TestLogger.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Common/TestLogger.cs
new file mode 100644
index 0000000..8253fb8
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Common/TestLogger.cs
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+namespace Apache.Ignite.Core.Tests.DotNetCore.Common
+{
+ using System;
+ using System.Diagnostics;
+ using System.Globalization;
+ using System.IO;
+ using Apache.Ignite.Core.Log;
+
+ /// <summary>
+ /// 'dotnet test' swallows console output. This logger writes to a file to overcome this.
+ /// </summary>
+ internal class TestLogger : ILogger
+ {
+ /** */
+ public static readonly TestLogger Instance = new TestLogger();
+
+ /** */
+ private readonly StreamWriter _file;
+
+ /// <summary>
+ /// Prevents a default instance of the <see cref="TestLogger"/> class from being created.
+ /// </summary>
+ private TestLogger()
+ {
+ var binDir = Path.GetDirectoryName(GetType().Assembly.Location);
+ var file = Path.Combine(binDir, "dotnet-test.log");
+
+ if (File.Exists(file))
+ {
+ File.Delete(file);
+ }
+
+ _file = File.AppendText(file);
+ }
+
+ /** <inheritdoc /> */
+ public void Log(LogLevel level, string message, object[] args, IFormatProvider formatProvider, string category,
+ string nativeErrorInfo, Exception ex)
+ {
+ lock (_file)
+ {
+ var text = args != null
+ ? string.Format(formatProvider ?? CultureInfo.InvariantCulture, message, args)
+ : message;
+
+ _file.WriteLine(text);
+ _file.Flush();
+ }
+ }
+
+ /** <inheritdoc /> */
+ public bool IsEnabled(LogLevel level)
+ {
+ return level > LogLevel.Debug;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Common/TestUtils.DotNetCore.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Common/TestUtils.DotNetCore.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Common/TestUtils.DotNetCore.cs
index 0f51593..c0586c3 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Common/TestUtils.DotNetCore.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Common/TestUtils.DotNetCore.cs
@@ -18,40 +18,54 @@
namespace Apache.Ignite.Core.Tests
{
using System;
- using System.Collections.Generic;
+ using System.Diagnostics;
using System.IO;
using System.Linq;
+ using Apache.Ignite.Core.Log;
+ using Apache.Ignite.Core.Tests.DotNetCore.Common;
public static partial class TestUtils
{
- /** */
- private static readonly IList<string> JvmOpts =
- new List<string>
- {
- "-Duser.timezone=UTC"
-
- // Uncomment to debug Java
- //"-Xdebug",
- //"-Xnoagent",
- //"-Djava.compiler=NONE",
- //"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"
- };
-
/// <summary>
/// Gets the default code-based test configuration.
/// </summary>
public static IgniteConfiguration GetTestConfiguration(string name = null)
{
+ TestLogger.Instance.Info("GetTestConfiguration: " + GetTestName());
+
return new IgniteConfiguration
{
DiscoverySpi = GetStaticDiscovery(),
Localhost = "127.0.0.1",
- JvmOptions = JvmOpts,
- IgniteInstanceName = name
+ JvmOptions = TestJavaOptions(),
+ IgniteInstanceName = name,
+ Logger = TestLogger.Instance
};
}
/// <summary>
+ /// Gets the name of the test.
+ /// </summary>
+ private static string GetTestName()
+ {
+ var st = new StackTrace();
+
+ for (var i = 0; i < st.FrameCount; i++)
+ {
+ var frame = st.GetFrame(i);
+ var method = frame.GetMethod();
+
+ if (method.DeclaringType != typeof(TestUtils)
+ && method.DeclaringType != typeof(TestBase))
+ {
+ return $"{method.DeclaringType.Name}.{method.Name}";
+ }
+ }
+
+ return st.GetFrames().Skip(2).Select(x => x.ToString()).FirstOrDefault() ?? "unknown";
+ }
+
+ /// <summary>
/// Creates a uniquely named, empty temporary directory on disk and returns the full path of that directory.
/// </summary>
/// <returns>The full path of the temporary directory.</returns>
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
index d965b72..4b9af70 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
@@ -81,7 +81,9 @@ namespace Apache.Ignite.Core.Tests.Client
{
Host = "localhost",
Port = 2000,
- PortRange = 1
+ PortRange = 1,
+ SocketSendBufferSize = 100,
+ SocketReceiveBufferSize = 50
}
};
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Log/CustomLoggerTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Log/CustomLoggerTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Log/CustomLoggerTest.cs
index e80bd3f..50d2dbf 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Log/CustomLoggerTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Log/CustomLoggerTest.cs
@@ -78,13 +78,6 @@ namespace Apache.Ignite.Core.Tests.Log
{
Assert.IsTrue(TestLogger.Entries.Any(x => x.Level == level), "No messages with level " + level);
}
-
- // Check IgniteHome and classpath messages.
- Assert.IsTrue(TestLogger.Entries.Any(x => x.Level == LogLevel.Debug &&
- x.Message == "Classpath resolved to: {0}"));
-
- Assert.IsTrue(TestLogger.Entries.Any(x => x.Level == LogLevel.Debug &&
- x.Message == "IGNITE_HOME resolved to: {0}"));
}
/// <summary>
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Common.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Common.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Common.cs
index 4f5f3f4..2430300 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Common.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Common.cs
@@ -46,7 +46,6 @@ namespace Apache.Ignite.Core.Tests
private const int DfltBusywaitSleepInterval = 200;
/** */
-
private static readonly IList<string> TestJvmOpts = Environment.Is64BitProcess
? new List<string>
{
@@ -230,8 +229,6 @@ namespace Apache.Ignite.Core.Tests
return false;
}
-
-
/// <summary>
/// Waits for condition, polling in busy wait loop.
/// </summary>
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
index 6deaa9b..5adb501 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
@@ -142,7 +142,7 @@
<Compile Include="Impl\DataRegionMetrics.cs" />
<Compile Include="Impl\PersistentStore\PersistentStoreMetrics.cs" />
<Compile Include="Impl\Shell.cs" />
- <Compile Include="Impl\Unmanaged\DllLoader.cs" />
+ <Compile Include="Impl\Unmanaged\Jni\DllLoader.cs" />
<Compile Include="Impl\Unmanaged\Jni\AppDomains.cs" />
<Compile Include="Impl\Unmanaged\Jni\CallbackDelegates.cs" />
<Compile Include="Impl\Unmanaged\Jni\Callbacks.cs" />
@@ -150,10 +150,13 @@
<Compile Include="Impl\Unmanaged\Jni\EnvDelegates.cs" />
<Compile Include="Impl\Unmanaged\Jni\Env.cs" />
<Compile Include="Impl\Unmanaged\Jni\EnvInterface.cs" />
+ <Compile Include="Impl\Unmanaged\Jni\JvmDll.cs" />
+ <Compile Include="Impl\Unmanaged\Jni\JvmInitArgs.cs" />
<Compile Include="Impl\Unmanaged\Jni\JvmInterface.cs" />
<Compile Include="Impl\PlatformDisposableTargetAdapter.cs" />
<Compile Include="Impl\PlatformJniTarget.cs" />
<Compile Include="Impl\Unmanaged\Jni\GlobalRef.cs" />
+ <Compile Include="Impl\Unmanaged\Jni\JvmOption.cs" />
<Compile Include="Impl\Unmanaged\Jni\MethodId.cs" />
<Compile Include="Impl\Unmanaged\Jni\NativeMethod.cs" />
<Compile Include="Impl\Unmanaged\Jni\JniResult.cs" />
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
index 29b8519..8c39091 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
@@ -847,10 +847,9 @@ namespace Apache.Ignite.Core
public string SpringConfigUrl { get; set; }
/// <summary>
- /// Path jvm.dll file. If not set, it's location will be determined
- /// using JAVA_HOME environment variable.
- /// If path is neither set nor determined automatically, an exception
- /// will be thrown.
+ /// Path to jvm.dll (libjvm.so on Linux, libjvm.dylib on Mac) file.
+ /// If not set, it's location will be determined using JAVA_HOME environment variable.
+ /// If path is neither set nor determined automatically, an exception will be thrown.
/// </summary>
public string JvmDllPath { get; set; }
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs
index 41419ac..46b9ec5 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs
@@ -227,7 +227,7 @@ namespace Apache.Ignite.Core
CheckServerGc(cfg, log);
// 2. Create context.
- IgniteUtils.LoadDlls(cfg.JvmDllPath, log);
+ JvmDll.Load(cfg.JvmDllPath, log);
var cbs = IgniteManager.CreateJvmContext(cfg, log);
var env = cbs.Jvm.AttachCurrentThread();
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientSocket.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientSocket.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientSocket.cs
index e565f31..078927b 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientSocket.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientSocket.cs
@@ -213,11 +213,19 @@ namespace Apache.Ignite.Core.Impl.Client
{
var socket = new Socket(ipEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
{
- SendBufferSize = cfg.SocketSendBufferSize,
- ReceiveBufferSize = cfg.SocketReceiveBufferSize,
NoDelay = cfg.TcpNoDelay
};
+ if (cfg.SocketSendBufferSize != IgniteClientConfiguration.DefaultSocketBufferSize)
+ {
+ socket.SendBufferSize = cfg.SocketSendBufferSize;
+ }
+
+ if (cfg.SocketReceiveBufferSize != IgniteClientConfiguration.DefaultSocketBufferSize)
+ {
+ socket.ReceiveBufferSize = cfg.SocketReceiveBufferSize;
+ }
+
socket.Connect(ipEndPoint);
return socket;
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteManager.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteManager.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteManager.cs
index ce84003..47260a7 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteManager.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteManager.cs
@@ -108,6 +108,14 @@ namespace Apache.Ignite.Core.Impl
/// <returns>JVM.</returns>
private static Jvm CreateJvm(IgniteConfiguration cfg, ILogger log)
{
+ // Do not bother with classpath when JVM exists.
+ var jvm = Jvm.Get(true);
+
+ if (jvm != null)
+ {
+ return jvm;
+ }
+
var cp = Classpath.CreateClasspath(cfg, log: log);
var jvmOpts = GetMergedJvmOptions(cfg);
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteUtils.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteUtils.cs
index 022a5ed..aff028e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteUtils.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteUtils.cs
@@ -19,9 +19,7 @@ namespace Apache.Ignite.Core.Impl
{
using System;
using System.Collections.Generic;
- using System.Globalization;
using System.IO;
- using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
@@ -31,9 +29,6 @@ namespace Apache.Ignite.Core.Impl
using Apache.Ignite.Core.Impl.Binary;
using Apache.Ignite.Core.Impl.Cluster;
using Apache.Ignite.Core.Impl.Common;
- using Apache.Ignite.Core.Impl.Unmanaged;
- using Apache.Ignite.Core.Log;
- using Microsoft.Win32;
using BinaryReader = Apache.Ignite.Core.Impl.Binary.BinaryReader;
/// <summary>
@@ -41,49 +36,9 @@ namespace Apache.Ignite.Core.Impl
/// </summary>
internal static class IgniteUtils
{
- /** Environment variable: JAVA_HOME. */
- private const string EnvJavaHome = "JAVA_HOME";
-
- /** Lookup paths. */
- private static readonly string[] JvmDllLookupPaths = Os.IsWindows
- ? new[]
- {
- // JRE paths
- @"bin\server",
- @"bin\client",
-
- // JDK paths
- @"jre\bin\server",
- @"jre\bin\client",
- @"jre\bin\default"
- }
- : new[]
- {
- // JRE paths
- "lib/amd64/server",
- "lib/amd64/client",
-
- // JDK paths
- "jre/lib/amd64/server",
- "jre/lib/amd64/client"
- };
-
- /** Registry lookup paths. */
- private static readonly string[] JreRegistryKeys =
- {
- @"Software\JavaSoft\Java Runtime Environment",
- @"Software\Wow6432Node\JavaSoft\Java Runtime Environment"
- };
-
- /** Jvm dll file name. */
- internal static readonly string FileJvmDll = Os.IsWindows ? "jvm.dll" : "libjvm.so";
-
/** Prefix for temp directory names. */
private const string DirIgniteTmp = "Ignite_";
- /** Loaded. */
- private static bool _loaded;
-
/** Thread-local random. */
[ThreadStatic]
private static Random _rnd;
@@ -127,25 +82,6 @@ namespace Apache.Ignite.Core.Impl
}
/// <summary>
- /// Load JVM DLL if needed.
- /// </summary>
- /// <param name="configJvmDllPath">JVM DLL path from config.</param>
- /// <param name="log">Log.</param>
- public static void LoadDlls(string configJvmDllPath, ILogger log)
- {
- if (_loaded)
- {
- log.Debug("JNI dll is already loaded.");
- return;
- }
-
- // 1. Load JNI dll.
- LoadJvmDll(configJvmDllPath, log);
-
- _loaded = true;
- }
-
- /// <summary>
/// Create new instance of specified class.
/// </summary>
/// <param name="typeName">Class name</param>
@@ -195,185 +131,7 @@ namespace Apache.Ignite.Core.Impl
}
}
- /// <summary>
- /// Loads the JVM DLL.
- /// </summary>
- private static void LoadJvmDll(string configJvmDllPath, ILogger log)
- {
- var messages = new List<string>();
- foreach (var dllPath in GetJvmDllPaths(configJvmDllPath))
- {
- log.Debug("Trying to load JVM dll from [option={0}, path={1}]...", dllPath.Key, dllPath.Value);
-
- var errInfo = LoadDll(dllPath.Value, FileJvmDll);
- if (errInfo == null)
- {
- log.Debug("jvm.dll successfully loaded from [option={0}, path={1}]", dllPath.Key, dllPath.Value);
- return;
- }
-
- var message = string.Format(CultureInfo.InvariantCulture, "[option={0}, path={1}, error={2}]",
- dllPath.Key, dllPath.Value, errInfo);
- messages.Add(message);
-
- log.Debug("Failed to load jvm.dll: " + message);
-
- if (dllPath.Value == configJvmDllPath)
- break; // if configJvmDllPath is specified and is invalid - do not try other options
- }
-
- if (!messages.Any()) // not loaded and no messages - everything was null
- messages.Add(string.Format(CultureInfo.InvariantCulture,
- "Please specify IgniteConfiguration.JvmDllPath or {0}.", EnvJavaHome));
-
- if (messages.Count == 1)
- throw new IgniteException(string.Format(CultureInfo.InvariantCulture, "Failed to load {0} ({1})",
- FileJvmDll, messages[0]));
-
- var combinedMessage =
- messages.Aggregate((x, y) => string.Format(CultureInfo.InvariantCulture, "{0}\n{1}", x, y));
-
- throw new IgniteException(string.Format(CultureInfo.InvariantCulture, "Failed to load {0}:\n{1}",
- FileJvmDll, combinedMessage));
- }
-
- /// <summary>
- /// Try loading DLLs first using file path, then using it's simple name.
- /// </summary>
- /// <param name="filePath"></param>
- /// <param name="simpleName"></param>
- /// <returns>Null in case of success, error info in case of failure.</returns>
- private static string LoadDll(string filePath, string simpleName)
- {
- string res = null;
-
- if (filePath != null)
- {
- res = DllLoader.Load(filePath);
-
- if (res == null)
- {
- return null; // Success.
- }
- }
-
- // Failed to load using file path, fallback to simple name.
- var res2 = DllLoader.Load(simpleName);
-
- if (res2 == null)
- {
- return null; // Success.
- }
-
- return res;
- }
-
- /// <summary>
- /// Gets the JVM DLL paths in order of lookup priority.
- /// </summary>
- private static IEnumerable<KeyValuePair<string, string>> GetJvmDllPaths(string configJvmDllPath)
- {
- if (!string.IsNullOrEmpty(configJvmDllPath))
- {
- yield return new KeyValuePair<string, string>("IgniteConfiguration.JvmDllPath", configJvmDllPath);
- }
-
- var javaHomeDir = Environment.GetEnvironmentVariable(EnvJavaHome);
-
- if (!string.IsNullOrEmpty(javaHomeDir))
- {
- foreach (var path in JvmDllLookupPaths)
- {
- yield return
- new KeyValuePair<string, string>(EnvJavaHome, Path.Combine(javaHomeDir, path, FileJvmDll));
- }
- }
-
- foreach (var keyValuePair in GetJvmDllPathsFromRegistry().Concat(GetJvmDllPathsFromSymlink()))
- {
- yield return keyValuePair;
- }
- }
-
- /// <summary>
- /// Gets Jvm dll paths from Windows registry.
- /// </summary>
- private static IEnumerable<KeyValuePair<string, string>> GetJvmDllPathsFromRegistry()
- {
- if (!Os.IsWindows)
- {
- yield break;
- }
-
- foreach (var regPath in JreRegistryKeys)
- {
- using (var jSubKey = Registry.LocalMachine.OpenSubKey(regPath))
- {
- if (jSubKey == null)
- continue;
-
- var curVer = jSubKey.GetValue("CurrentVersion") as string;
-
- // Current version comes first
- var versions = new[] {curVer}.Concat(jSubKey.GetSubKeyNames().Where(x => x != curVer));
- foreach (var ver in versions.Where(v => !string.IsNullOrEmpty(v)))
- {
- using (var verKey = jSubKey.OpenSubKey(ver))
- {
- var dllPath = verKey == null ? null : verKey.GetValue("RuntimeLib") as string;
-
- if (dllPath != null)
- yield return new KeyValuePair<string, string>(verKey.Name, dllPath);
- }
- }
- }
- }
- }
-
- /// <summary>
- /// Gets the Jvm dll paths from symlink.
- /// </summary>
- private static IEnumerable<KeyValuePair<string, string>> GetJvmDllPathsFromSymlink()
- {
- if (Os.IsWindows)
- {
- yield break;
- }
-
- const string javaExec = "/usr/bin/java";
- if (!File.Exists(javaExec))
- {
- yield break;
- }
-
- var file = Shell.BashExecute("readlink -f /usr/bin/java");
- // /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java
-
- var dir = Path.GetDirectoryName(file);
- // /usr/lib/jvm/java-8-openjdk-amd64/jre/bin
-
- if (dir == null)
- {
- yield break;
- }
-
- var libFolder = Path.GetFullPath(Path.Combine(dir, "../lib/"));
- if (!Directory.Exists(libFolder))
- {
- yield break;
- }
-
- // Predefined path: /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so
- yield return new KeyValuePair<string, string>(javaExec,
- Path.Combine(libFolder, "amd64", "server", FileJvmDll));
-
- // Last resort - custom paths:
- foreach (var f in Directory.GetFiles(libFolder, FileJvmDll, SearchOption.AllDirectories))
- {
- yield return new KeyValuePair<string, string>(javaExec, f);
- }
- }
/// <summary>
/// Creates a uniquely named, empty temporary directory on disk and returns the full path of that directory.
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Shell.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Shell.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Shell.cs
index e48c8fe..45678f0 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Shell.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Shell.cs
@@ -18,10 +18,12 @@
namespace Apache.Ignite.Core.Impl
{
using System.Diagnostics;
+ using System.Diagnostics.CodeAnalysis;
/// <summary>
/// Shell utils (cmd/bash).
/// </summary>
+ [ExcludeFromCodeCoverage]
internal static class Shell
{
/// <summary>
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/DllLoader.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/DllLoader.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/DllLoader.cs
deleted file mode 100644
index 61de8e4..0000000
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/DllLoader.cs
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- */
-
-namespace Apache.Ignite.Core.Impl.Unmanaged
-{
- using System;
- using System.ComponentModel;
- using System.Diagnostics.CodeAnalysis;
- using System.Runtime.InteropServices;
-
- /// <summary>
- /// Dynamically loads unmanaged DLLs with respect to current platform.
- /// </summary>
- internal static class DllLoader
- {
- /** Lazy symbol binding. */
- private const int RtldLazy = 1;
-
- /** Global symbol access. */
- private const int RtldGlobal = 8;
-
- /// <summary>
- /// ERROR_BAD_EXE_FORMAT constant.
- /// </summary>
- // ReSharper disable once InconsistentNaming
- private const int ERROR_BAD_EXE_FORMAT = 193;
-
- /// <summary>
- /// ERROR_MOD_NOT_FOUND constant.
- /// </summary>
- // ReSharper disable once InconsistentNaming
- private const int ERROR_MOD_NOT_FOUND = 126;
-
- /// <summary>
- /// Loads specified DLL.
- /// </summary>
- /// <returns>Null when successful; error message otherwise.</returns>
- public static string Load(string dllPath)
- {
- if (Os.IsWindows)
- {
- return NativeMethodsWindows.LoadLibrary(dllPath) == IntPtr.Zero
- ? FormatWin32Error(Marshal.GetLastWin32Error()) ?? "Unknown error"
- : null;
- }
-
- if (Os.IsLinux)
- {
- if (Os.IsMono)
- {
- return NativeMethodsMono.dlopen(dllPath, RtldGlobal | RtldLazy) == IntPtr.Zero
- ? GetErrorText(NativeMethodsMono.dlerror())
- : null;
- }
-
- if (Os.IsNetCore)
- {
- return NativeMethodsCore.dlopen(dllPath, RtldGlobal | RtldLazy) == IntPtr.Zero
- ? GetErrorText(NativeMethodsCore.dlerror())
- : null;
- }
-
- return NativeMethodsLinux.dlopen(dllPath, RtldGlobal | RtldLazy) == IntPtr.Zero
- ? GetErrorText(NativeMethodsLinux.dlerror())
- : null;
- }
-
- throw new InvalidOperationException("Unsupported OS: " + Environment.OSVersion);
- }
-
- /// <summary>
- /// Gets the error text.
- /// </summary>
- private static string GetErrorText(IntPtr charPtr)
- {
- return Marshal.PtrToStringAnsi(charPtr) ?? "Unknown error";
- }
-
- /// <summary>
- /// Formats the Win32 error.
- /// </summary>
- [ExcludeFromCodeCoverage]
- private static string FormatWin32Error(int errorCode)
- {
- if (errorCode == ERROR_BAD_EXE_FORMAT)
- {
- var mode = Environment.Is64BitProcess ? "x64" : "x86";
-
- return string.Format("DLL could not be loaded (193: ERROR_BAD_EXE_FORMAT). " +
- "This is often caused by x64/x86 mismatch. " +
- "Current process runs in {0} mode, and DLL is not {0}.", mode);
- }
-
- if (errorCode == ERROR_MOD_NOT_FOUND)
- {
- return "DLL could not be loaded (126: ERROR_MOD_NOT_FOUND). " +
- "This can be caused by missing dependencies. ";
- }
-
- return string.Format("{0}: {1}", errorCode, new Win32Exception(errorCode).Message);
- }
-
- /// <summary>
- /// Windows.
- /// </summary>
- private static class NativeMethodsWindows
- {
- [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
- [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi, BestFitMapping = false,
- ThrowOnUnmappableChar = true)]
- internal static extern IntPtr LoadLibrary(string filename);
- }
-
- /// <summary>
- /// Linux.
- /// </summary>
- private static class NativeMethodsLinux
- {
- [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
- [DllImport("libdl.so", SetLastError = true, CharSet = CharSet.Ansi, BestFitMapping = false,
- ThrowOnUnmappableChar = true)]
- internal static extern IntPtr dlopen(string filename, int flags);
-
- [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
- [DllImport("libdl.so", SetLastError = true, CharSet = CharSet.Ansi, BestFitMapping = false,
- ThrowOnUnmappableChar = true)]
- internal static extern IntPtr dlerror();
- }
-
- /// <summary>
- /// libdl.so depends on libc6-dev on Linux, use Mono instead.
- /// </summary>
- private static class NativeMethodsMono
- {
- [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
- [DllImport("__Internal", SetLastError = true, CharSet = CharSet.Ansi, BestFitMapping = false,
- ThrowOnUnmappableChar = true)]
- internal static extern IntPtr dlopen(string filename, int flags);
-
- [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
- [DllImport("__Internal", SetLastError = true, CharSet = CharSet.Ansi, BestFitMapping = false,
- ThrowOnUnmappableChar = true)]
- internal static extern IntPtr dlerror();
- }
-
- /// <summary>
- /// libdl.so depends on libc6-dev on Linux, use libcoreclr instead.
- /// </summary>
- private static class NativeMethodsCore
- {
- [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
- [DllImport("libcoreclr.so", SetLastError = true, CharSet = CharSet.Ansi, BestFitMapping = false,
- ThrowOnUnmappableChar = true)]
- internal static extern IntPtr dlopen(string filename, int flags);
-
- [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
- [DllImport("libcoreclr.so", SetLastError = true, CharSet = CharSet.Ansi, BestFitMapping = false,
- ThrowOnUnmappableChar = true)]
- internal static extern IntPtr dlerror();
- }
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/DllLoader.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/DllLoader.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/DllLoader.cs
new file mode 100644
index 0000000..578135d
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/DllLoader.cs
@@ -0,0 +1,210 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Unmanaged.Jni
+{
+ using System;
+ using System.Collections.Generic;
+ using System.ComponentModel;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Runtime.InteropServices;
+
+ /// <summary>
+ /// Dynamically loads unmanaged DLLs with respect to current platform.
+ /// </summary>
+ internal static class DllLoader
+ {
+ /** Lazy symbol binding. */
+ private const int RtldLazy = 1;
+
+ /** Global symbol access. */
+ private const int RtldGlobal = 8;
+
+ /// <summary>
+ /// ERROR_BAD_EXE_FORMAT constant.
+ /// </summary>
+ // ReSharper disable once InconsistentNaming
+ private const int ERROR_BAD_EXE_FORMAT = 193;
+
+ /// <summary>
+ /// ERROR_MOD_NOT_FOUND constant.
+ /// </summary>
+ // ReSharper disable once InconsistentNaming
+ private const int ERROR_MOD_NOT_FOUND = 126;
+
+ /// <summary>
+ /// Loads specified DLL.
+ /// </summary>
+ /// <returns>Library handle and error message.</returns>
+ public static KeyValuePair<IntPtr, string> Load(string dllPath)
+ {
+ if (Os.IsWindows)
+ {
+ var ptr = NativeMethodsWindows.LoadLibrary(dllPath);
+ return new KeyValuePair<IntPtr, string>(ptr, ptr == IntPtr.Zero
+ ? FormatWin32Error(Marshal.GetLastWin32Error()) ?? "Unknown error"
+ : null);
+ }
+
+ if (Os.IsMacOs)
+ {
+ var ptr = NativeMethodsMacOs.dlopen(dllPath, RtldGlobal | RtldLazy);
+ return new KeyValuePair<IntPtr, string>(ptr, ptr == IntPtr.Zero
+ ? GetErrorText(NativeMethodsMacOs.dlerror())
+ : null);
+ }
+
+ if (Os.IsLinux)
+ {
+ if (Os.IsMono)
+ {
+ var ptr = NativeMethodsMono.dlopen(dllPath, RtldGlobal | RtldLazy);
+ return new KeyValuePair<IntPtr, string>(ptr, ptr == IntPtr.Zero
+ ? GetErrorText(NativeMethodsMono.dlerror())
+ : null);
+ }
+
+ if (Os.IsNetCore)
+ {
+ var ptr = NativeMethodsCore.dlopen(dllPath, RtldGlobal | RtldLazy);
+ return new KeyValuePair<IntPtr, string>(ptr, ptr == IntPtr.Zero
+ ? GetErrorText(NativeMethodsCore.dlerror())
+ : null);
+ }
+
+ var lptr = NativeMethodsLinux.dlopen(dllPath, RtldGlobal | RtldLazy);
+ return new KeyValuePair<IntPtr, string>(lptr, lptr == IntPtr.Zero
+ ? GetErrorText(NativeMethodsLinux.dlerror())
+ : null);
+ }
+
+ throw new InvalidOperationException("Unsupported OS: " + Environment.OSVersion);
+ }
+
+ /// <summary>
+ /// Gets the error text.
+ /// </summary>
+ private static string GetErrorText(IntPtr charPtr)
+ {
+ return Marshal.PtrToStringAnsi(charPtr) ?? "Unknown error";
+ }
+
+ /// <summary>
+ /// Formats the Win32 error.
+ /// </summary>
+ [ExcludeFromCodeCoverage]
+ private static string FormatWin32Error(int errorCode)
+ {
+ if (errorCode == ERROR_BAD_EXE_FORMAT)
+ {
+ var mode = Environment.Is64BitProcess ? "x64" : "x86";
+
+ return string.Format("DLL could not be loaded (193: ERROR_BAD_EXE_FORMAT). " +
+ "This is often caused by x64/x86 mismatch. " +
+ "Current process runs in {0} mode, and DLL is not {0}.", mode);
+ }
+
+ if (errorCode == ERROR_MOD_NOT_FOUND)
+ {
+ return "DLL could not be loaded (126: ERROR_MOD_NOT_FOUND). " +
+ "This can be caused by missing dependencies. ";
+ }
+
+ return string.Format("{0}: {1}", errorCode, new Win32Exception(errorCode).Message);
+ }
+
+ /// <summary>
+ /// Windows.
+ /// </summary>
+ private static class NativeMethodsWindows
+ {
+ [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
+ [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi, BestFitMapping = false,
+ ThrowOnUnmappableChar = true)]
+ internal static extern IntPtr LoadLibrary(string filename);
+ }
+
+ /// <summary>
+ /// Linux.
+ /// </summary>
+ private static class NativeMethodsLinux
+ {
+ [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
+ [DllImport("libdl.so", SetLastError = true, CharSet = CharSet.Ansi, BestFitMapping = false,
+ ThrowOnUnmappableChar = true)]
+ internal static extern IntPtr dlopen(string filename, int flags);
+
+ [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
+ [DllImport("libdl.so", SetLastError = true, CharSet = CharSet.Ansi, BestFitMapping = false,
+ ThrowOnUnmappableChar = true)]
+ internal static extern IntPtr dlerror();
+ }
+
+ /// <summary>
+ /// libdl.so depends on libc6-dev on Linux, use Mono instead.
+ /// </summary>
+ private static class NativeMethodsMono
+ {
+ [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
+ [DllImport("__Internal", SetLastError = true, CharSet = CharSet.Ansi, BestFitMapping = false,
+ ThrowOnUnmappableChar = true)]
+ internal static extern IntPtr dlopen(string filename, int flags);
+
+ [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
+ [DllImport("__Internal", SetLastError = true, CharSet = CharSet.Ansi, BestFitMapping = false,
+ ThrowOnUnmappableChar = true)]
+ internal static extern IntPtr dlerror();
+ }
+
+ /// <summary>
+ /// libdl.so depends on libc6-dev on Linux, use libcoreclr instead.
+ /// </summary>
+ private static class NativeMethodsCore
+ {
+ [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
+ [DllImport("libcoreclr.so", SetLastError = true, CharSet = CharSet.Ansi, BestFitMapping = false,
+ ThrowOnUnmappableChar = true)]
+ internal static extern IntPtr dlopen(string filename, int flags);
+
+ [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
+ [DllImport("libcoreclr.so", SetLastError = true, CharSet = CharSet.Ansi, BestFitMapping = false,
+ ThrowOnUnmappableChar = true)]
+ internal static extern IntPtr dlerror();
+ }
+
+ /// <summary>
+ /// macOs uses "libSystem.dylib".
+ /// </summary>
+ internal static class NativeMethodsMacOs
+ {
+ [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
+ [DllImport("libSystem.dylib", CharSet = CharSet.Ansi, BestFitMapping = false,
+ ThrowOnUnmappableChar = true)]
+ internal static extern IntPtr dlopen(string filename, int flags);
+
+ [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
+ [DllImport("libSystem.dylib", CharSet = CharSet.Ansi, BestFitMapping = false,
+ ThrowOnUnmappableChar = true)]
+ internal static extern IntPtr dlerror();
+
+ [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
+ [DllImport("libSystem.dylib", CharSet = CharSet.Ansi, BestFitMapping = false,
+ ThrowOnUnmappableChar = true)]
+ internal static extern IntPtr dlsym(IntPtr handle, string symbol);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/Jvm.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/Jvm.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/Jvm.cs
index ebff15b..3699751 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/Jvm.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/Jvm.cs
@@ -126,11 +126,11 @@ namespace Apache.Ignite.Core.Impl.Unmanaged.Jni
/// <summary>
/// Gets the JVM.
/// </summary>
- public static Jvm Get()
+ public static Jvm Get(bool ignoreMissing = false)
{
var res = _instance;
- if (res == null)
+ if (res == null && !ignoreMissing)
{
throw new IgniteException("JVM has not been created.");
}
@@ -205,7 +205,7 @@ namespace Apache.Ignite.Core.Impl.Unmanaged.Jni
int existingJvmCount;
// Use existing JVM if present.
- var res = JniNativeMethods.JNI_GetCreatedJavaVMs(out jvm, 1, out existingJvmCount);
+ var res = JvmDll.Instance.GetCreatedJvms(out jvm, 1, out existingJvmCount);
if (res != JniResult.Success)
{
throw new IgniteException("JNI_GetCreatedJavaVMs failed: " + res);
@@ -238,7 +238,7 @@ namespace Apache.Ignite.Core.Impl.Unmanaged.Jni
}
IntPtr env;
- res = JniNativeMethods.JNI_CreateJavaVM(out jvm, out env, &args);
+ res = JvmDll.Instance.CreateJvm(out jvm, out env, &args);
if (res != JniResult.Success)
{
throw new IgniteException("JNI_CreateJavaVM failed: " + res);
@@ -255,78 +255,6 @@ namespace Apache.Ignite.Core.Impl.Unmanaged.Jni
del = (T) (object) Marshal.GetDelegateForFunctionPointer(ptr, typeof(T));
}
- /// <summary>
- /// JavaVMOption.
- /// </summary>
- [SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable")]
- [StructLayout(LayoutKind.Sequential, Pack = 0)]
- private struct JvmOption
- {
- public IntPtr optionString;
- private readonly IntPtr extraInfo;
- }
-
- /// <summary>
- /// JavaVMInitArgs.
- /// </summary>
- [StructLayout(LayoutKind.Sequential, Pack = 0)]
- private struct JvmInitArgs
- {
- public int version;
- public int nOptions;
- public JvmOption* options;
- private readonly byte ignoreUnrecognized;
- }
-
- private static class JniNativeMethods
- {
- internal static JniResult JNI_CreateJavaVM(out IntPtr pvm, out IntPtr penv,
- JvmInitArgs* args)
- {
- return Os.IsWindows
- ? JniNativeMethodsWindows.JNI_CreateJavaVM(out pvm, out penv, args)
- : JniNativeMethodsLinux.JNI_CreateJavaVM(out pvm, out penv, args);
- }
-
- internal static JniResult JNI_GetCreatedJavaVMs(out IntPtr pvm, int size, out int size2)
- {
- return Os.IsWindows
- ? JniNativeMethodsWindows.JNI_GetCreatedJavaVMs(out pvm, size, out size2)
- : JniNativeMethodsLinux.JNI_GetCreatedJavaVMs(out pvm, size, out size2);
- }
- }
-
- /// <summary>
- /// DLL imports.
- /// </summary>
- private static class JniNativeMethodsWindows
- {
- [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
- [DllImport("jvm.dll", CallingConvention = CallingConvention.StdCall)]
- internal static extern JniResult JNI_CreateJavaVM(out IntPtr pvm, out IntPtr penv,
- JvmInitArgs* args);
-
- [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
- [DllImport("jvm.dll", CallingConvention = CallingConvention.StdCall)]
- internal static extern JniResult JNI_GetCreatedJavaVMs(out IntPtr pvm, int size,
- [Out] out int size2);
- }
-
- /// <summary>
- /// DLL imports.
- /// </summary>
- private static class JniNativeMethodsLinux
- {
- [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
- [DllImport("libjvm.so", CallingConvention = CallingConvention.StdCall)]
- internal static extern JniResult JNI_CreateJavaVM(out IntPtr pvm, out IntPtr penv,
- JvmInitArgs* args);
-
- [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
- [DllImport("libjvm.so", CallingConvention = CallingConvention.StdCall)]
- internal static extern JniResult JNI_GetCreatedJavaVMs(out IntPtr pvm, int size,
- [Out] out int size2);
- }
/// <summary>
/// Provides access to <see cref="Callbacks"/> instance in the default AppDomain.
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/JvmDll.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/JvmDll.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/JvmDll.cs
new file mode 100644
index 0000000..28c85ef
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/JvmDll.cs
@@ -0,0 +1,414 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Unmanaged.Jni
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Globalization;
+ using System.IO;
+ using System.Linq;
+ using System.Runtime.InteropServices;
+ using Apache.Ignite.Core.Common;
+ using Apache.Ignite.Core.Log;
+ using Microsoft.Win32;
+
+ /// <summary>
+ /// Jvm.dll loader (libjvm.so on Linux, libjvm.dylib on macOs).
+ /// </summary>
+ internal class JvmDll
+ {
+ /** Cached instance. */
+ private static JvmDll _instance;
+
+ /** Environment variable: JAVA_HOME. */
+ private const string EnvJavaHome = "JAVA_HOME";
+
+ /** Lookup paths. */
+ private static readonly string[] JvmDllLookupPaths = Os.IsWindows
+ ? new[]
+ {
+ // JRE paths
+ @"bin\server",
+ @"bin\client",
+
+ // JDK paths
+ @"jre\bin\server",
+ @"jre\bin\client",
+ @"jre\bin\default"
+ }
+ : new[]
+ {
+ // JRE paths
+ "lib/server",
+ "lib/client",
+ "lib/amd64/server",
+ "lib/amd64/client",
+
+ // JDK paths
+ "jre/lib/server",
+ "jre/lib/client",
+ "jre/lib/amd64/server",
+ "jre/lib/amd64/client"
+ };
+
+ /** Registry lookup paths. */
+ private static readonly string[] JreRegistryKeys =
+ {
+ @"Software\JavaSoft\Java Runtime Environment",
+ @"Software\Wow6432Node\JavaSoft\Java Runtime Environment"
+ };
+
+ /** Jvm dll file name. */
+ internal static readonly string FileJvmDll = Os.IsWindows
+ ? "jvm.dll"
+ : Os.IsMacOs
+ ? "libjvm.dylib"
+ : "libjvm.so";
+
+ /** */
+ private unsafe delegate JniResult CreateJvmDel(out IntPtr pvm, out IntPtr penv, JvmInitArgs* args);
+
+ /** */
+ private delegate JniResult GetCreatedJvmsDel(out IntPtr pvm, int size, out int size2);
+
+ /** */
+ private readonly CreateJvmDel _createJvm;
+
+ /** */
+ private readonly GetCreatedJvmsDel _getCreatedJvms;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JvmDll"/> class.
+ /// </summary>
+ private unsafe JvmDll(IntPtr ptr)
+ {
+ if (Os.IsMacOs)
+ {
+ if (ptr == IntPtr.Zero)
+ {
+ // Retrieve already loaded dll by name.
+ // This happens in default AppDomain when Ignite starts in another domain.
+ var res = DllLoader.Load(FileJvmDll);
+ ptr = res.Key;
+
+ if (res.Key == IntPtr.Zero)
+ {
+ throw new IgniteException(
+ string.Format("{0} has not been loaded: {1}", FileJvmDll, res.Value));
+ }
+ }
+
+ // dlopen + DllImport combo does not work on macOs, so we have to call dlsym manually.
+ var createJvmPtr = DllLoader.NativeMethodsMacOs.dlsym(ptr, "JNI_CreateJavaVM");
+ _createJvm = (CreateJvmDel) Marshal.GetDelegateForFunctionPointer(createJvmPtr, typeof(CreateJvmDel));
+
+ var getJvmsPtr = DllLoader.NativeMethodsMacOs.dlsym(ptr, "JNI_GetCreatedJavaVMs");
+ _getCreatedJvms = (GetCreatedJvmsDel) Marshal.GetDelegateForFunctionPointer(getJvmsPtr,
+ typeof(GetCreatedJvmsDel));
+ }
+ else if (Os.IsWindows)
+ {
+ _createJvm = JniNativeMethodsWindows.JNI_CreateJavaVM;
+ _getCreatedJvms = JniNativeMethodsWindows.JNI_GetCreatedJavaVMs;
+ }
+ else
+ {
+ _createJvm = JniNativeMethodsLinux.JNI_CreateJavaVM;
+ _getCreatedJvms = JniNativeMethodsLinux.JNI_GetCreatedJavaVMs;
+ }
+ }
+
+ /// <summary>
+ /// Gets the instance.
+ /// </summary>
+ public static JvmDll Instance
+ {
+ get { return _instance ?? (_instance = new JvmDll(IntPtr.Zero)); }
+ }
+
+ /// <summary>
+ /// Creates the JVM.
+ /// </summary>
+ public unsafe JniResult CreateJvm(out IntPtr pvm, out IntPtr penv, JvmInitArgs* args)
+ {
+ return _createJvm(out pvm, out penv, args);
+ }
+
+ /// <summary>
+ /// Gets the created JVMS.
+ /// </summary>
+ public JniResult GetCreatedJvms(out IntPtr pvm, int size, out int size2)
+ {
+ return _getCreatedJvms(out pvm, size, out size2);
+ }
+
+ /// <summary>
+ /// Loads the JVM DLL into process memory.
+ /// </summary>
+ public static void Load(string configJvmDllPath, ILogger log)
+ {
+ // Load only once.
+ // Locking is performed by the caller three, omit here.
+ if (_instance != null)
+ {
+ log.Debug("JNI dll is already loaded.");
+ return;
+ }
+
+ var messages = new List<string>();
+ foreach (var dllPath in GetJvmDllPaths(configJvmDllPath))
+ {
+ log.Debug("Trying to load {0} from [option={1}, path={2}]...", FileJvmDll, dllPath.Key, dllPath.Value);
+
+ var res = LoadDll(dllPath.Value, FileJvmDll);
+ if (res.Key != IntPtr.Zero)
+ {
+ log.Debug("{0} successfully loaded from [option={1}, path={2}]",
+ FileJvmDll, dllPath.Key, dllPath.Value);
+
+ _instance = new JvmDll(res.Key);
+
+ return;
+ }
+
+ var message = string.Format(CultureInfo.InvariantCulture, "[option={0}, path={1}, error={2}]",
+ dllPath.Key, dllPath.Value, res.Value);
+ messages.Add(message);
+
+ log.Debug("Failed to load {0}: {1}", FileJvmDll, message);
+
+ if (dllPath.Value == configJvmDllPath)
+ break; // if configJvmDllPath is specified and is invalid - do not try other options
+ }
+
+ if (!messages.Any()) // not loaded and no messages - everything was null
+ {
+ messages.Add(string.Format(CultureInfo.InvariantCulture,
+ "Please specify IgniteConfiguration.JvmDllPath or {0}.", EnvJavaHome));
+ }
+
+ if (messages.Count == 1)
+ {
+ throw new IgniteException(string.Format(CultureInfo.InvariantCulture, "Failed to load {0} ({1})",
+ FileJvmDll, messages[0]));
+ }
+
+ var combinedMessage =
+ messages.Aggregate((x, y) => string.Format(CultureInfo.InvariantCulture, "{0}\n{1}", x, y));
+
+ throw new IgniteException(string.Format(CultureInfo.InvariantCulture, "Failed to load {0}:\n{1}",
+ FileJvmDll, combinedMessage));
+ }
+
+ /// <summary>
+ /// Try loading DLLs first using file path, then using it's simple name.
+ /// </summary>
+ /// <param name="filePath"></param>
+ /// <param name="simpleName"></param>
+ /// <returns>Null in case of success, error info in case of failure.</returns>
+ private static KeyValuePair<IntPtr, string> LoadDll(string filePath, string simpleName)
+ {
+ var res = new KeyValuePair<IntPtr, string>();
+
+ if (filePath != null)
+ {
+ res = DllLoader.Load(filePath);
+
+ if (res.Key != IntPtr.Zero)
+ {
+ return res; // Success.
+ }
+ }
+
+ // Failed to load using file path, fallback to simple name.
+ var res2 = DllLoader.Load(simpleName);
+
+ if (res2.Key != IntPtr.Zero)
+ {
+ return res2; // Success.
+ }
+
+ return res.Value != null ? res : res2;
+ }
+
+ /// <summary>
+ /// Gets the JVM DLL paths in order of lookup priority.
+ /// </summary>
+ private static IEnumerable<KeyValuePair<string, string>> GetJvmDllPaths(string configJvmDllPath)
+ {
+ if (!string.IsNullOrEmpty(configJvmDllPath))
+ {
+ yield return new KeyValuePair<string, string>("IgniteConfiguration.JvmDllPath", configJvmDllPath);
+ }
+
+ var javaHomeDir = Environment.GetEnvironmentVariable(EnvJavaHome);
+
+ if (!string.IsNullOrEmpty(javaHomeDir))
+ {
+ foreach (var path in JvmDllLookupPaths)
+ {
+ yield return
+ new KeyValuePair<string, string>(EnvJavaHome, Path.Combine(javaHomeDir, path, FileJvmDll));
+ }
+ }
+
+ foreach (var keyValuePair in
+ GetJvmDllPathsWindows()
+ .Concat(GetJvmDllPathsLinux())
+ .Concat(GetJvmDllPathsMacOs()))
+ {
+ yield return keyValuePair;
+ }
+ }
+
+ /// <summary>
+ /// Gets Jvm dll paths from Windows registry.
+ /// </summary>
+ private static IEnumerable<KeyValuePair<string, string>> GetJvmDllPathsWindows()
+ {
+ if (!Os.IsWindows)
+ {
+ yield break;
+ }
+
+ foreach (var regPath in JreRegistryKeys)
+ {
+ using (var jSubKey = Registry.LocalMachine.OpenSubKey(regPath))
+ {
+ if (jSubKey == null)
+ continue;
+
+ var curVer = jSubKey.GetValue("CurrentVersion") as string;
+
+ // Current version comes first
+ var versions = new[] {curVer}.Concat(jSubKey.GetSubKeyNames().Where(x => x != curVer));
+
+ foreach (var ver in versions.Where(v => !string.IsNullOrEmpty(v)))
+ {
+ using (var verKey = jSubKey.OpenSubKey(ver))
+ {
+ var dllPath = verKey == null ? null : verKey.GetValue("RuntimeLib") as string;
+
+ if (dllPath != null)
+ yield return new KeyValuePair<string, string>(verKey.Name, dllPath);
+ }
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets the Jvm dll paths from /usr/bin/java symlink.
+ /// </summary>
+ private static IEnumerable<KeyValuePair<string, string>> GetJvmDllPathsLinux()
+ {
+ if (Os.IsWindows || Os.IsMacOs)
+ {
+ yield break;
+ }
+
+ const string javaExec = "/usr/bin/java";
+ if (!File.Exists(javaExec))
+ {
+ yield break;
+ }
+
+ var file = Shell.BashExecute("readlink -f /usr/bin/java");
+ // /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java
+
+ var dir = Path.GetDirectoryName(file);
+ // /usr/lib/jvm/java-8-openjdk-amd64/jre/bin
+
+ if (dir == null)
+ {
+ yield break;
+ }
+
+ var libFolder = Path.GetFullPath(Path.Combine(dir, "../lib/"));
+ if (!Directory.Exists(libFolder))
+ {
+ yield break;
+ }
+
+ // Predefined path: /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so
+ yield return new KeyValuePair<string, string>(javaExec,
+ Path.Combine(libFolder, "amd64", "server", FileJvmDll));
+
+ // Last resort - custom paths:
+ foreach (var f in Directory.GetFiles(libFolder, FileJvmDll, SearchOption.AllDirectories))
+ {
+ yield return new KeyValuePair<string, string>(javaExec, f);
+ }
+ }
+
+ /// <summary>
+ /// Gets the JVM DLL paths on macOs.
+ /// </summary>
+ private static IEnumerable<KeyValuePair<string, string>> GetJvmDllPathsMacOs()
+ {
+ const string jvmDir = "/Library/Java/JavaVirtualMachines";
+
+ if (!Directory.Exists(jvmDir))
+ {
+ yield break;
+ }
+
+ const string subDir = "Contents/Home";
+
+ foreach (var dir in Directory.GetDirectories(jvmDir))
+ {
+ foreach (var path in JvmDllLookupPaths)
+ {
+ yield return
+ new KeyValuePair<string, string>(dir, Path.Combine(dir, subDir, path, FileJvmDll));
+ }
+ }
+ }
+
+ /// <summary>
+ /// DLL imports.
+ /// </summary>
+ private static unsafe class JniNativeMethodsWindows
+ {
+ [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
+ [DllImport("jvm.dll", CallingConvention = CallingConvention.StdCall)]
+ internal static extern JniResult JNI_CreateJavaVM(out IntPtr pvm, out IntPtr penv, JvmInitArgs* args);
+
+ [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
+ [DllImport("jvm.dll", CallingConvention = CallingConvention.StdCall)]
+ internal static extern JniResult JNI_GetCreatedJavaVMs(out IntPtr pvm, int size,
+ [Out] out int size2);
+ }
+
+ /// <summary>
+ /// DLL imports.
+ /// </summary>
+ private static unsafe class JniNativeMethodsLinux
+ {
+ [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
+ [DllImport("libjvm.so", CallingConvention = CallingConvention.StdCall)]
+ internal static extern JniResult JNI_CreateJavaVM(out IntPtr pvm, out IntPtr penv, JvmInitArgs* args);
+
+ [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
+ [DllImport("libjvm.so", CallingConvention = CallingConvention.StdCall)]
+ internal static extern JniResult JNI_GetCreatedJavaVMs(out IntPtr pvm, int size,
+ [Out] out int size2);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/JvmInitArgs.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/JvmInitArgs.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/JvmInitArgs.cs
new file mode 100644
index 0000000..0b3c655
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/JvmInitArgs.cs
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Unmanaged.Jni
+{
+ using System.Runtime.InteropServices;
+
+ /// <summary>
+ /// JavaVMInitArgs.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 0)]
+ internal unsafe struct JvmInitArgs
+ {
+ public int version;
+ public int nOptions;
+ public JvmOption* options;
+ private readonly byte ignoreUnrecognized;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/JvmOption.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/JvmOption.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/JvmOption.cs
new file mode 100644
index 0000000..3e239d1
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Jni/JvmOption.cs
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Unmanaged.Jni
+{
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Runtime.InteropServices;
+
+ /// <summary>
+ /// JavaVMOption.
+ /// </summary>
+ [SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable")]
+ [StructLayout(LayoutKind.Sequential, Pack = 0)]
+ internal struct JvmOption
+ {
+ public IntPtr optionString;
+ private readonly IntPtr extraInfo;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Os.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Os.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Os.cs
index 22ab447..535aa4c 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Os.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/Os.cs
@@ -39,6 +39,7 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
|| platform == PlatformID.Win32S
|| platform == PlatformID.Win32Windows;
+ IsMacOs = IsLinux && Shell.BashExecute("uname").Contains("Darwin");
IsMono = Type.GetType("Mono.Runtime") != null;
IsNetCore = !IsMono;
}
@@ -62,5 +63,10 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
/// Linux.
/// </summary>
public static bool IsLinux { get; private set; }
+
+ /// <summary>
+ /// MacOs.
+ /// </summary>
+ public static bool IsMacOs { get; private set; }
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/bf432ef4/modules/platforms/dotnet/Apache.Ignite.ndproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.ndproj b/modules/platforms/dotnet/Apache.Ignite.ndproj
index aa30019..5ed9e3c 100644
--- a/modules/platforms/dotnet/Apache.Ignite.ndproj
+++ b/modules/platforms/dotnet/Apache.Ignite.ndproj
@@ -2478,7 +2478,7 @@ select new {
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[//<Name>Avoid the Singleton pattern</Name>
warnif count > 0
from t in Application.Types
-where !t.IsStatic && !t.IsAbstract && (t.IsClass || t.IsStructure) && t.Name != "Jvm"
+where !t.IsStatic && !t.IsAbstract && (t.IsClass || t.IsStructure) && t.Name != "Jvm" && t.Name != "JvmDll"
// All ctors of a singleton are private
where t.Constructors.Where(ctor => !ctor.IsPrivate).Count() == 0