//******************************************************************************************************
// Common.cs - Gbtc
//
// Copyright © 2012, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), 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.opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 04/03/2006 - J. Ritchie Carroll
// Generated original version of source code.
// 12/13/2007 - Darrell Zuercher
// Edited code comments.
// 09/08/2008 - J. Ritchie Carroll
// Converted to C#.
// 02/13/2009 - Josh L. Patterson
// Edited Code Comments.
// 09/14/2009 - Stephen C. Wills
// Added new header and license agreement.
// 09/17/2009 - Pinal C. Patel
// Modified GetApplicationType() to remove dependency on HttpContext.Current.
// 09/28/2010 - Pinal C. Patel
// Cached the current ApplicationType returned by GetApplicationType() for better performance.
// 12/05/2010 - Pinal C. Patel
// Added an overload for TypeConvertToString() that takes CultureInfo as a parameter.
// 12/07/2010 - Pinal C. Patel
// Updated TypeConvertToString() to return an empty string if the passed in value is null.
// 03/09/2011 - Pinal C. Patel
// Moved UpdateType enumeration from GSF.Services.ServiceProcess namespace for broader usage.
// 04/07/2011 - J. Ritchie Carroll
// Added ToNonNullNorEmptyString() and ToNonNullNorWhiteSpace() extensions.
// 12/14/2012 - Starlynn Danyelle Gilliam
// Modified Header.
//
//******************************************************************************************************
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Web.Hosting;
using GSF.Collections;
using GSF.Console;
using GSF.IO;
using GSF.Reflection;
using Microsoft.Win32;
namespace GSF
{
#region [ Enumerations ]
///
/// Specifies the type of the application.
///
public enum ApplicationType
{
///
/// Application is of unknown type.
///
Unknown = 0,
///
/// Application doesn't require a subsystem.
///
Native = 1,
///
/// Application runs in the Windows GUI subsystem.
///
WindowsGui = 2,
///
/// Application runs in the Windows character subsystem.
///
WindowsCui = 3,
///
/// Application runs in the OS/2 character subsystem.
///
OS2Cui = 5,
///
/// Application runs in the POSIX character subsystem.
///
PosixCui = 7,
///
/// Application is a native Win9x driver.
///
NativeWindows = 8,
///
/// Application runs in the Windows CE subsystem.
///
WindowsCEGui = 9,
///
/// The application is a web site or web application.
///
Web = 100
}
///
/// Indicates the type of update.
///
public enum UpdateType
{
///
/// Update is informational.
///
Information,
///
/// Update is a warning.
///
Warning,
///
/// Update is an alarm.
///
Alarm
}
#endregion
// This is the location for handy miscellaneous functions that are difficult to categorize elsewhere. For the most
// part these functions may have the most value in a Visual Basic application which supports importing functions
// down to a class level, e.g.: Imports GSF.Common
///
/// Defines common global functions.
///
public static class Common
{
private static ApplicationType? s_applicationType;
private static string s_osPlatformName;
private static PlatformID s_osPlatformID = PlatformID.Win32S;
///
/// Determines if the current system is a POSIX style environment.
///
///
///
/// Since a .NET application compiled under Mono can run under both Windows and Unix style platforms,
/// you can use this property to easily determine the current operating environment.
///
///
/// This property will return true for both MacOSX and Unix environments. Use the Platform property
/// of the to determine more specific platform type, e.g.,
/// MacOSX or Unix. Note that all flavors of Linux will show up as .
///
///
public static readonly bool IsPosixEnvironment = (Path.DirectorySeparatorChar == '/'); // This is how Mono source often checks this
///
/// Determines if the code base is currently running under Mono.
///
///
/// This property can be used to make a run-time determination if Windows or Mono based .NET is being used. However, it is
/// highly recommended to use the MONO compiler directive wherever possible instead of determining this at run-time.
///
public static bool IsMono = ((object)Type.GetType("Mono.Runtime") != null);
/// Returns one of two strongly-typed objects.
/// One of two objects, depending on the evaluation of given expression.
/// The expression you want to evaluate.
/// Returned if expression evaluates to True.
/// Returned if expression evaluates to False.
/// Return type used for immediate expression
///
/// This function acts as a strongly-typed immediate if (a.k.a. inline if).
///
/// It is expected that this function will only be used in languages that do not support ?: conditional operations, e.g., Visual Basic.NET.
/// In Visual Basic this function can be used as a strongly-typed IIf replacement by specifying "Imports GSF.Common".
///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T IIf(bool expression, T truePart, T falsePart)
{
return (expression ? truePart : falsePart);
}
/// Creates a strongly-typed Array.
/// New array of specified type.
/// Desired length of new array.
/// Return type for new array.
///
/// It is expected that this function will only be used in Visual Basic.NET.
///
/// The Array.CreateInstance provides better performance and more direct CLR access for array creation (not to
/// mention less confusion on the matter of array lengths) in VB.NET, however the returned System.Array is not
/// typed properly. This function properly casts the return array based on the type specification helping
/// when Option Strict is enabled.
///
///
///
///
/// Dim buffer As Byte() = CreateArray(Of Byte)(12)
/// Dim matrix As Integer()() = CreateArray(Of Integer())(10)
///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T[] CreateArray(int length)
{
// The following provides better performance than "Return New T(length) {}".
// ReSharper disable once UseArrayCreationExpression.1
return (T[])Array.CreateInstance(typeof(T), length);
}
/// Creates a strongly-typed Array with an initial value parameter.
/// New array of specified type.
/// Desired length of new array.
/// Value used to initialize all array elements.
/// Return type for new array.
///
/// It is expected that this function will only be used in Visual Basic.NET.
///
///
///
/// Dim elements As Integer() = CreateArray(12, -1)
/// Dim names As String() = CreateArray(100, "undefined")
///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T[] CreateArray(int length, T initialValue)
{
T[] typedArray = CreateArray(length);
// Initializes all elements with the default value.
for (int x = 0; x < typedArray.Length; x++)
{
typedArray[x] = initialValue;
}
return typedArray;
}
///
/// Gets the type of the currently executing application.
///
/// One of the values.
public static ApplicationType GetApplicationType()
{
if (s_applicationType.HasValue)
return s_applicationType.Value;
if (HostingEnvironment.IsHosted)
{
s_applicationType = ApplicationType.Web;
}
else
{
try
{
// References:
// - http://support.microsoft.com/kb/65122
// - http://support.microsoft.com/kb/90493/en-us
// - http://www.codeguru.com/cpp/w-p/system/misc/article.php/c2897/
// We will always have an entry assembly for windows application.
FileStream exe = new FileStream(AssemblyInfo.EntryAssembly.Location, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
byte[] dosHeader = new byte[64];
byte[] exeHeader = new byte[248];
byte[] subSystem = new byte[2];
exe.Read(dosHeader, 0, dosHeader.Length);
exe.Seek(BitConverter.ToInt16(dosHeader, 60), SeekOrigin.Begin);
exe.Read(exeHeader, 0, exeHeader.Length);
exe.Close();
Buffer.BlockCopy(exeHeader, 92, subSystem, 0, 2);
s_applicationType = ((ApplicationType)(LittleEndian.ToInt16(subSystem, 0)));
}
catch
{
// We are unable to determine the application type.
s_applicationType = ApplicationType.Unknown;
}
}
return s_applicationType.Value;
}
///
/// Gets the operating system
///
/// The operating system .
///
/// This function will properly detect the platform ID, even if running on Mac.
///
public static PlatformID GetOSPlatformID()
{
if (s_osPlatformID != PlatformID.Win32S)
return s_osPlatformID;
s_osPlatformID = Environment.OSVersion.Platform;
if (s_osPlatformID == PlatformID.Unix)
{
// Environment.OSVersion.Platform can report Unix when running on Mac OS X
try
{
s_osPlatformID = Command.Execute("uname").StandardOutput.StartsWith("Darwin", StringComparison.OrdinalIgnoreCase) ? PlatformID.MacOSX : PlatformID.Unix;
}
catch
{
// Fall back on looking for Mac specific root folders:
if (Directory.Exists("/Applications") && Directory.Exists("/System") && Directory.Exists("/Users") && Directory.Exists("/Volumes"))
s_osPlatformID = PlatformID.MacOSX;
}
}
return s_osPlatformID;
}
///
/// Gets the operating system product name.
///
/// Operating system product name.
public static string GetOSProductName()
{
if ((object)s_osPlatformName != null)
return s_osPlatformName;
switch (GetOSPlatformID())
{
case PlatformID.Unix:
case PlatformID.MacOSX:
// Call sw_vers on Mac to get product name and version information, Linux could have this
try
{
string output = Command.Execute("sw_vers").StandardOutput;
Dictionary kvps = output.ParseKeyValuePairs('\n', ':');
if (kvps.Count > 0)
s_osPlatformName = kvps.Values.Select(val => val.Trim()).ToDelimitedString(" ");
}
catch
{
s_osPlatformName = null;
}
if (string.IsNullOrEmpty(s_osPlatformName))
{
// Try some common ways to get product name on Linux, some might work on Mac
try
{
foreach (string fileName in FilePath.GetFileList("/etc/*release*"))
{
using (StreamReader reader = new StreamReader(fileName))
{
string line = reader.ReadLine();
while ((object)line != null)
{
if (line.StartsWith("PRETTY_NAME", StringComparison.OrdinalIgnoreCase) && !line.Contains('#'))
{
string[] parts = line.Split('=');
if (parts.Length == 2)
{
s_osPlatformName = parts[1].Replace("\"", "");
break;
}
}
line = reader.ReadLine();
}
}
if (!string.IsNullOrEmpty(s_osPlatformName))
break;
}
}
catch
{
try
{
string output = Command.Execute("lsb_release", "-a").StandardOutput;
Dictionary kvps = output.ParseKeyValuePairs('\n', ':');
if (kvps.TryGetValue("Description", out s_osPlatformName) && !string.IsNullOrEmpty(s_osPlatformName))
s_osPlatformName = s_osPlatformName.Trim();
}
catch
{
s_osPlatformName = null;
}
}
}
break;
default:
// Get Windows product name
try
{
s_osPlatformName = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "ProductName", null).ToString();
}
catch
{
s_osPlatformName = null;
}
break;
}
if (string.IsNullOrWhiteSpace(s_osPlatformName))
s_osPlatformName = GetOSPlatformID().ToString();
if (IsMono)
s_osPlatformName += " using Mono";
return s_osPlatformName;
}
///
/// Gets the memory usage by the current process.
///
/// Memory usage by the current process.
public static long GetProcessMemory()
{
long processMemory = Environment.WorkingSet;
if (processMemory == 0 && IsPosixEnvironment)
{
try
{
double percentOfTotal;
long totalMemory;
// Get total system memory
using (PerformanceCounter counter = new PerformanceCounter("Mono Memory", "Total Physical Memory"))
totalMemory = counter.RawValue;
// Get percent of total memory used by current process
string output = Command.Execute("ps", string.Format("-p {0} -o %mem", Process.GetCurrentProcess().Id)).StandardOutput;
string[] lines = output.Split('\n');
if (lines.Length > 1 && double.TryParse(lines[1].Trim(), out percentOfTotal))
processMemory = (long)Math.Round(percentOfTotal / 100.0D * totalMemory);
}
catch
{
processMemory = -1;
}
}
return processMemory;
}
// The following "ToNonNullString" methods extend all class based objects. Note that these extension methods can be
// called even if the base object is null, hence the value of these methods. Our philosophy for this project has been
// "not" to apply extensions to all objects (this to avoid general namespace pollution) and make sure extensions are
// grouped together in their own source file (e.g., StringExtensions.cs); however these items do apply to all items
// and are essentially type-less hence their location in the "Common" class. These extension methods are at least
// limited to classes and won't show up on native types and custom structures.
///
/// Converts value to string; null objects (or DBNull objects) will return an empty string ("").
///
/// of to convert to string.
/// Value to convert to string.
/// as a string; if is null, empty string ("") will be returned.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string ToNonNullString(this T value) where T : class
{
return ((object)value == null || value is DBNull ? "" : value.ToString());
}
///
/// Converts value to string; null objects (or DBNull objects) will return specified .
///
/// of to convert to string.
/// Value to convert to string.
/// to return if is null.
/// as a string; if is null, will be returned.
/// cannot be null.
public static string ToNonNullString(this T value, string nonNullValue) where T : class
{
if ((object)nonNullValue == null)
throw new ArgumentNullException("nonNullValue");
return ((object)value == null || value is DBNull ? nonNullValue : value.ToString());
}
// We handle strings as a special version of the ToNullNullString extension to handle documentation a little differently
///
/// Makes sure returned string value is not null; if this string is null, empty string ("") will be returned.
///
/// to verify is not null.
/// value; if is null, empty string ("") will be returned.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string ToNonNullString(this string value)
{
return ((object)value == null ? "" : value);
}
///
/// Converts value to string; null objects, DBNull objects or empty strings will return specified .
///
/// of to convert to string.
/// Value to convert to string.
/// to return if is null.
/// as a string; if is null, DBNull or an empty string will be returned.
/// must not be null or an empty string.
public static string ToNonNullNorEmptyString(this T value, string nonNullNorEmptyValue = " ") where T : class
{
if (string.IsNullOrEmpty(nonNullNorEmptyValue))
throw new ArgumentException("Must not be null or an empty string", "nonNullNorEmptyValue");
if ((object)value == null || value is DBNull)
return nonNullNorEmptyValue;
string valueAsString = value.ToString();
return (string.IsNullOrEmpty(valueAsString) ? nonNullNorEmptyValue : valueAsString);
}
///
/// Converts value to string; null objects, DBNull objects, empty strings or all white space strings will return specified .
///
/// of to convert to string.
/// Value to convert to string.
/// to return if is null.
/// as a string; if is null, DBNull, empty or all white space, will be returned.
/// must not be null, an empty string or white space.
public static string ToNonNullNorWhiteSpace(this T value, string nonNullNorWhiteSpaceValue = "_") where T : class
{
if (string.IsNullOrWhiteSpace(nonNullNorWhiteSpaceValue))
throw new ArgumentException("Must not be null, an empty string or white space", "nonNullNorWhiteSpaceValue");
if ((object)value == null || value is DBNull)
return nonNullNorWhiteSpaceValue;
string valueAsString = value.ToString();
return (string.IsNullOrWhiteSpace(valueAsString) ? nonNullNorWhiteSpaceValue : valueAsString);
}
///
/// Converts to a using an appropriate .
///
/// Value to convert to a .
/// converted to a .
///
///
/// If fails, the value's ToString() value will be returned.
/// Returned value will never be null, if no value exists an empty string ("") will be returned.
///
///
/// You can use the string extension method to
/// convert the string back to its original .
///
///
public static string TypeConvertToString(object value)
{
return TypeConvertToString(value, null);
}
///
/// Converts to a using an appropriate .
///
/// Value to convert to a .
/// to use for the conversion.
/// converted to a .
///
///
/// If fails, the value's ToString() value will be returned.
/// Returned value will never be null, if no value exists an empty string ("") will be returned.
///
///
/// You can use the string extension method to
/// convert the string back to its original .
///
///
public static string TypeConvertToString(object value, CultureInfo culture)
{
// Don't proceed further if value is null.
if ((object)value == null)
return string.Empty;
// If value is already a string, no need to attempt conversion
string valueAsString = value as string;
if ((object)valueAsString != null)
return valueAsString;
// Initialize culture info if not specified.
if ((object)culture == null)
culture = CultureInfo.InvariantCulture;
try
{
// Attempt to use type converter to set field value
TypeConverter converter = TypeDescriptor.GetConverter(value);
return converter.ConvertToString(null, culture, value).ToNonNullString();
}
catch
{
// Otherwise just call object's ToString method
return value.ToNonNullString();
}
}
/// Gets a high-resolution number of seconds, including fractional seconds, that have
/// elapsed since 12:00:00 midnight, January 1, 0001.
public static double SystemTimer
{
get
{
return Ticks.ToSeconds(DateTime.UtcNow.Ticks);
}
}
/// Determines if given item is equal to its default value (e.g., null or 0.0).
/// Object to evaluate.
/// Result of evaluation as a .
///
/// Native types default to zero, not null, therefore this can be used to evaluate if an item is its default (i.e., uninitialized) value.
///
public static bool IsDefaultValue(object item)
{
// Only reference types can be null, therefore null is its default value
if ((object)item == null)
return true;
Type itemType = item.GetType();
if (!itemType.IsValueType)
return false;
// Handle common types
IConvertible convertible = item as IConvertible;
if ((object)convertible != null)
{
try
{
switch (convertible.GetTypeCode())
{
case TypeCode.Boolean:
return ((bool)item == default(bool));
case TypeCode.SByte:
return ((sbyte)item == default(sbyte));
case TypeCode.Byte:
return ((byte)item == default(byte));
case TypeCode.Int16:
return ((short)item == default(short));
case TypeCode.UInt16:
return ((ushort)item == default(ushort));
case TypeCode.Int32:
return ((int)item == default(int));
case TypeCode.UInt32:
return ((uint)item == default(uint));
case TypeCode.Int64:
return ((long)item == default(long));
case TypeCode.UInt64:
return ((ulong)item == default(ulong));
case TypeCode.Single:
return ((float)item == default(float));
case TypeCode.Double:
return ((double)item == default(double));
case TypeCode.Decimal:
return ((decimal)item == default(decimal));
case TypeCode.Char:
return ((char)item == default(char));
case TypeCode.DateTime:
return ((DateTime)item == default(DateTime));
}
}
catch (InvalidCastException)
{
// An exception here indicates that the item is a custom type that
// lied about its type code. The type should still be instantiable,
// so we can ignore this exception
}
}
// Handle custom value types
return ((ValueType)item).Equals(Activator.CreateInstance(itemType));
}
/// Determines if given item is a reference type.
/// Object to evaluate.
/// Result of evaluation as a .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsReference(object item)
{
return !(item is ValueType);
}
/// Determines if given item is a reference type but not a string.
/// Object to evaluate.
/// Result of evaluation as a .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNonStringReference(object item)
{
return (IsReference(item) && !(item is string));
}
/// Determines if given item is numeric.
/// Object to evaluate.
/// Result of evaluation as a .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNumeric(object item)
{
IConvertible convertible = item as IConvertible;
if ((object)convertible != null)
{
switch (convertible.GetTypeCode())
{
case TypeCode.Boolean:
case TypeCode.SByte:
case TypeCode.Byte:
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Int64:
case TypeCode.UInt64:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
return true;
case TypeCode.Char:
case TypeCode.String:
double result;
return double.TryParse(convertible.ToString(null), out result);
}
}
return false;
}
/// Returns the smallest item from a list of parameters.
/// Return type that is the minimum value in the .
/// A variable number of parameters of the specified type.
/// Result is the minimum value of type in the .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Min(params T[] itemList)
{
return itemList.Min();
}
/// Returns the largest item from a list of parameters.
/// Return type that is the maximum value in the .
/// A variable number of parameters of the specified type .
/// Result is the maximum value of type in the .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Max(params T[] itemList)
{
return itemList.Max();
}
/// Returns the value that is neither the largest nor the smallest.
/// of the objects passed to and returned from this method.
/// Value 1.
/// Value 2.
/// Value 3.
/// Result is the value that is neither the largest nor the smallest.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Mid(T value1, T value2, T value3) where T : IComparable
{
if ((object)value1 == null)
throw new ArgumentNullException("value1");
if ((object)value2 == null)
throw new ArgumentNullException("value2");
if ((object)value3 == null)
throw new ArgumentNullException("value3");
int comp1to2 = value1.CompareTo(value2);
int comp1to3 = value1.CompareTo(value3);
int comp2to3 = value2.CompareTo(value3);
// If 3 is the smallest, pick the smaller of 1 and 2
if (comp1to3 >= 0 && comp2to3 >= 0)
return (comp1to2 <= 0) ? value1 : value2;
// If 2 is the smallest, pick the smaller of 1 and 3
if (comp1to2 >= 0 && comp2to3 <= 0)
return (comp1to3 <= 0) ? value1 : value3;
// 1 is the smallest so pick the smaller of 2 and 3
return (comp2to3 <= 0) ? value2 : value3;
}
#region [ Old Code ]
///// Returns the smallest item from a list of parameters.
///// A variable number of parameters of type
///// Result is the minimum value of type in the .
//public static object Min(params object[] itemList)
//{
// return itemList.Min