#region Copyright
/*
* Copyright (c) 2005,2006,2007, OpenMI Association
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenMI Association nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY "OpenMI Association" ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL "OpenMI Association" BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#endregion
using System;
using System.Collections;
using System.ComponentModel;
using System.Reflection;
using System.IO;
using System.Globalization;
using System.Security.Policy;
using System.Configuration.Assemblies;
namespace Oatc.OpenMI.Sdk.DevelopmentSupport
{
///
/// Number of methods for general operations on objects. They comprise:
/// 1. instantiating objects given a class name
/// 2. deep copy of objects
///
public class ObjectSupport
{
private static ArrayList _assemblyList = new ArrayList();
#region Copy objects
///
/// Gets a deep copy of a specified object.
/// Deep copying copies all primitive and enumeration properties and the properties for which MetaInfo "ObjectCopy" is set to true
///
/// The object to be copied
/// The copied object
public static object GetCopy(object source)
{
object copy = ObjectSupport.GetInstance(source.GetType());
if (copy != null)
{
ObjectSupport.Copy (source, copy);
}
return copy;
}
///
/// Gets a deep copy of a specified object and copies referenced files
/// Deep copying copies all primitive and enumeration properties and the properties for which MetaInfo "ObjectCopy" is set to true
///
/// The object to be copied
/// The path in which copied files will be positioned (relative to original position)
/// The copied object
public static object GetCopy(object source, string path)
{
if (source == null)
{
return null;
}
if (source is FileSystemInfo)
{
if ((path != null) && (!path.Trim().Equals("")))
{
return CopyFile ((FileSystemInfo) source, path);
}
else
{
return ObjectSupport.GetInstance(source.GetType(), source.ToString());
}
}
object copy = ObjectSupport.GetInstance(source.GetType(), source.ToString());
if (copy != null)
{
ObjectSupport.Copy (source, copy, path);
}
return copy;
}
///
/// Creates an object which is a deep copy fo a source object, including copying of referenced file
/// Deep copying copies all primitive and enumeration properties and the properties for which MetaInfo "ObjectCopy" is set to true
///
/// The object to be copied
/// Lookup table for already copied objects
/// Path where files are copied to
///
private static object GetCopy(object source, Hashtable copiedObjects, string path)
{
if (copiedObjects[source] != null)
{
return copiedObjects[source];
}
else if (source is FileSystemInfo)
{
object copiedFile = CopyFile ((FileSystemInfo) source, path);
copiedObjects.Add (source, copiedFile);
return copiedFile;
}
else
{
object copy = ObjectSupport.GetInstance(source.GetType());
if (copy != null)
{
copiedObjects.Add (source, copy);
ObjectSupport.Copy (source, copy, copiedObjects, path);
}
return copy;
}
}
///
/// Deep copies all properties of source into the properties of target
/// Deep copying copies all primitive and enumeration properties and the properties for which MetaInfo "ObjectCopy" is set to true
///
/// The source object
/// The target object
public static void Copy(object source, object target)
{
ObjectSupport.Copy (source, target, "");
}
///
/// Deep copies all properties of source into the properties of target, including files
/// Deep copying copies all primitive and enumeration properties and the properties for which MetaInfo "ObjectCopy" is set to true
///
/// The source object
/// The target object
/// Path where files are copied to
public static void Copy(object source, object target, string path)
{
ObjectSupport.Copy (source, target, new Hashtable(), path);
}
///
/// Gets the deep copy
///
/// The object to be copied
/// The object which will be the copy
/// Collection of objects and their copied equivalents. Will be populated and queried during copy.
/// Relative path to location where copied files will reside
private static void Copy(object source, object target, Hashtable copiedObjects, string path)
{
Copy (source, target, copiedObjects, path, true);
}
///
/// Gets the deep copy
///
/// The object to be copied
/// The object which will be the copy
/// Collection of objects and their copied equivalents. Will be populated and queried during copy.
/// Relative path to location where files will be copied to
/// Indicates whether the new object should refer to a copy or to the same object
private static void Copy(object source, object target, Hashtable copiedObjects, string path, bool copyValue)
{
if (source is IList)
{
IList copiedArray = (IList) target;
copiedArray.Clear();
for (int j = 0; j < ((IList) source).Count; j++)
{
object copiedArrayValue = ((IList) source)[j];
if (copyValue)
{
copiedArrayValue = ObjectSupport.GetCopy (copiedArrayValue, copiedObjects, path);
}
copiedArray.Add (copiedArrayValue);
}
}
else if (source is IDictionary)
{
IDictionary copiedArray = (IDictionary) target;
copiedArray.Clear();
IDictionaryEnumerator dictionaryEnumerator = ((IDictionary) source).GetEnumerator();
while (dictionaryEnumerator.MoveNext())
{
object copiedArrayKey = dictionaryEnumerator.Key;
object copiedArrayValue = dictionaryEnumerator.Value;
if (copyValue)
{
copiedArrayKey = ObjectSupport.GetCopy (copiedArrayKey, copiedObjects, path);
copiedArrayValue = ObjectSupport.GetCopy (copiedArrayValue, copiedObjects, path);
}
if (!copiedArray.Contains (copiedArrayKey))
{
copiedArray.Add (copiedArrayKey, copiedArrayValue);
}
}
}
// Special handling for files
else if (source is FileSystemInfo)
{
if (copyValue && (path != null) && (!path.Trim().Equals("")))
{
object copiedValue = CopyFile ((FileSystemInfo) source, path);
}
}
else
{
PropertyInfo[] property = source.GetType().GetProperties();
for (int i = 0; i < property.Length; i++)
{
object sourceValue = property[i].GetValue (source, null);
if (sourceValue != null)
{
// Default copied value. This is just a reference to the original value
object copiedValue = sourceValue;
// If the value has been copied before, use the same copied equivalent
if (copiedObjects.ContainsKey (sourceValue))
{
copiedValue = copiedObjects[sourceValue];
}
else
{
// Determine whether the property is to be copied
bool copyPropertyValue = (Boolean) MetaInfo.GetAttributeDefault (source.GetType(), property[i].Name, "ObjectCopy", false);
if (copyPropertyValue)
{
if (property[i].CanWrite)
{
copiedValue = ObjectSupport.GetCopy (sourceValue, copiedObjects, path);
}
else
{
object targetValue = property[i].GetValue (target, null);
Copy (sourceValue, targetValue, copiedObjects, path);
}
}
else if ((sourceValue is IList) || (sourceValue is IDictionary))
{
object targetValue = property[i].GetValue (target, null);
Copy (sourceValue, targetValue, copiedObjects, path, copyPropertyValue);
}
}
// Populate the target object
if (property[i].CanWrite)
{
property[i].SetValue (target, copiedValue, null);
}
if (!copiedObjects.Contains(sourceValue))
{
copiedObjects.Add (sourceValue, copiedValue);
}
}
}
}
}
///
/// Gets a copy of a file.
/// If the file doesn't exist, the copied file will not exist neither.
///
/// The file or directory to be copied
/// The relative path (starting from the location of the original file) to the directory where the file will be copied to
/// The copied file
private static FileSystemInfo CopyFile (FileSystemInfo fileSystem, string path)
{
if ((path != null) && (path.Trim() != ""))
{
if (fileSystem is FileInfo)
{
FileInfo file = (FileInfo) fileSystem;
FileInfo targetFile = FileSupport.ExpandRelativePath(file.Directory, path + "\\" + file.Name);
if (File.Exists(file.FullName))
{
if (!targetFile.Directory.Exists)
{
targetFile.Directory.Create();
}
file.CopyTo(targetFile.FullName, true);
}
else
{
if (File.Exists(targetFile.FullName))
{
targetFile.Delete();
}
}
return new FileInfo(targetFile.FullName);
}
if (fileSystem is DirectoryInfo)
{
DirectoryInfo dir = (DirectoryInfo) fileSystem;
DirectoryInfo targetDir = FileSupport.ExpandRelativeDirectory(dir, path);
if (Directory.Exists(dir.FullName))
{
DirCopy (dir.FullName, targetDir.FullName, false);
}
else
{
if (Directory.Exists(targetDir.FullName))
{
Directory.Delete (targetDir.FullName);
}
}
return targetDir;
}
return null;
}
else
{
return fileSystem;
}
}
private static void DirCopy(string srcdir, string destdir, bool recursive)
{
DirectoryInfo dir;
FileInfo[] files;
DirectoryInfo[] dirs;
string tmppath;
//determine if the destination directory exists, if not create it
if (! Directory.Exists(destdir))
{
Directory.CreateDirectory(destdir);
}
dir = new DirectoryInfo(srcdir);
//if the source dir doesn't exist, throw
if (! dir.Exists)
{
throw new ArgumentException("source dir doesn't exist -> " + srcdir);
}
//get all files in the current dir
files = dir.GetFiles();
//loop through each file
foreach(FileInfo file in files)
{
//create the path to where this file should be in destdir
tmppath=Path.Combine(destdir, file.Name);
//copy file to dest dir
file.CopyTo(tmppath, false);
}
//cleanup
files = null;
//if not recursive, all work is done
if (! recursive)
{
return;
}
//otherwise, get dirs
dirs = dir.GetDirectories();
//loop through each sub directory in the current dir
foreach(DirectoryInfo subdir in dirs)
{
//create the path to the directory in destdir
tmppath = Path.Combine(destdir, subdir.Name);
//recursively call this function over and over again
//with each new dir.
DirCopy(subdir.FullName, tmppath, recursive);
}
//cleanup
dirs = null;
dir = null;
}
#endregion
#region Assembly handling
///
/// Loads an assembly.
/// The assembly name can be either a full path to a file or a full or partial name of an assembly registered in the GAC.
/// An empty assembly name is ignored.
///
/// The assembly name
/// Assembly cannot be found in the GAC
public static void LoadAssembly(string assemblyName)
{
if ((assemblyName == null) || (assemblyName.Trim().Equals("")))
{
return;
}
Assembly assembly = null;
if (File.Exists(assemblyName))
{
FileInfo assemblyFile = new FileInfo(assemblyName);
foreach (Assembly loadedAssembly in _assemblyList)
{
if (loadedAssembly.Location.EndsWith(Path.DirectorySeparatorChar + assemblyFile.Name))
{
return;
}
}
assembly = Assembly.LoadFrom(assemblyFile.FullName);
}
else
{
try
{
// VS2005 fix
// The line below produces "System.Reflection.Assembly.LoadWithPartialName(string)' is obsolete:
// 'This method has been deprecated. Please use Assembly.Load() instead. " warning
// however for backwards compatibility we need to use this method,
// because some older XML configuration files still may use short assembly names
#pragma warning disable 0618
assembly = Assembly.LoadWithPartialName(assemblyName);
#pragma warning restore 0618
}
catch (FileNotFoundException e)
{
// bug in framework; assembly could be found
if (assembly == null)
{
throw e;
}
}
}
LoadAssembly (assembly);
}
///
/// Loads an assembly.
///
/// The assembly
public static void LoadAssembly (Assembly assembly)
{
if ((assembly != null) && !_assemblyList.Contains(assembly))
{
_assemblyList.Add (assembly);
}
}
///
/// Tells whether an assembly has been loaded already.
///
/// The assembly
/// Indication of loaded
public static bool IsLoadedAssembly (Assembly assembly)
{
return _assemblyList.Contains (assembly);
}
#endregion
#region Object instantiation
///
/// Gets the class object given a string describing the class. The following assemblies are queried:
/// 1. All assemblies loaded with ObjectSupport.LoadAssembly
/// 2. All assemblies which reside in the same directory as this assembly
///
/// The class name, including path with namespaces
/// The class object or null if not found
/// Class cannot be found
public static Type GetType(string ClassType)
{
if (ClassType == null)
{
return null;
}
Type type = Type.GetType(ClassType);
for (int i = 0; (i < _assemblyList.Count) && (type == null); i++)
{
Assembly assembly = (Assembly) _assemblyList[i];
if (assembly != null)
{
type = assembly.GetType(ClassType);
}
}
if (type == null)
{
throw new Exception("Cannot find class " + ClassType);
}
return type;
}
///
/// Creates a new object.
/// Types with an argumentless constructor can be created this way
///
/// Full class name of the object to be instantiated
/// New object, null if not possible
public static object GetInstance (string classType)
{
return ObjectSupport.GetInstance(ObjectSupport.GetType(classType));
}
///
/// Creates a new object using a base value (e.g. a string with its value).
/// Normally primitives, enumerations and some value types can be instantiated this way.
/// Also types with constructors having one argument can be instantiated.
///
/// Full class name of the object to be instantiated
/// Value which is passed as argument to the constructor
/// New object, null if not possible
public static object GetInstance (string classType, object baseValue)
{
return ObjectSupport.GetInstance(ObjectSupport.GetType(classType), baseValue, null);
}
///
/// Creates a new object.
/// Types with an argumentless constructor can be created this way
///
/// Class type of the object to be instantiated
/// New object, null if not possible
public static object GetInstance (Type type)
{
if (type == null)
{
return null;
}
Type[] types = new Type[0];
ConstructorInfo constructor = type.GetConstructor(types);
if (constructor != null)
{
return constructor.Invoke(null);
}
return null;
}
///
/// Creates a new object using a base value (e.g. a string with its value).
/// Normally primitives, enumerations and some value types can be instantiated this way.
/// Also types with constructors having one argument can be instantiated.
///
/// Class type of the object to be instantiated
/// Value which is passed as argument to the constructor
/// New object, null if not possible
public static object GetInstance (Type type, object baseValue)
{
return ObjectSupport.GetInstance (type, baseValue, null);
}
///
/// Creates a new object using a base value (e.g. a string with its value).
/// Normally primitives, enumerations and some value types can be instantiated this way.
/// Also types with constructors having one argument can be instantiated.
///
/// Class type of the object to be instantiated
/// Value which is passed as argument to the constructor
/// Culture info used for parsing the base value
/// New object, null if not possible
public static object GetInstance (Type type, object baseValue, CultureInfo culture)
{
if (type == null)
{
return null;
}
else if (type.IsEnum)
{
return Enum.Parse (type, baseValue.ToString(), true);
}
else if (type.Equals (typeof (String)))
{
return baseValue.ToString();
}
else if (type.Equals (typeof (Double)))
{
if (culture == null)
{
return Double.Parse (baseValue.ToString());
}
else
{
return Double.Parse (baseValue.ToString(), culture);
}
}
else if (type.Equals (typeof (Boolean)))
{
return Boolean.Parse (baseValue.ToString());
}
else if (type.Equals (typeof (Int16)))
{
return Int16.Parse (baseValue.ToString());
}
else if (type.Equals (typeof (Int32)))
{
return Int32.Parse (baseValue.ToString());
}
else if (type.Equals (typeof (Int64)))
{
return Int64.Parse (baseValue.ToString());
}
else if (type.Equals (typeof (DateTime)))
{
return DateTime.Parse (baseValue.ToString(), culture.DateTimeFormat);
}
else
{
Type[] types;
Type classType;
ConstructorInfo constructor;
if (baseValue != null)
{
types = new Type[1];
classType = type;
while (classType != null)
{
types[0] = baseValue.GetType();
while (types[0] != null)
{
constructor = classType.GetConstructor(types);
if (constructor != null)
{
Object[] arguments = new Object[1];
arguments[0] = baseValue;
Object instance = constructor.Invoke(arguments);
return instance;
}
else
{
types[0] = types[0].BaseType;
}
}
classType = classType.BaseType;
}
}
types = new Type[0];
classType = type;
while (classType != null)
{
constructor = type.GetConstructor(types);
if (constructor != null)
{
object instance = constructor.Invoke(null);
return instance;
}
classType = classType.BaseType;
}
return null;
}
}
#endregion
}
}