diff --git a/dotnet/framework/.gitignore b/dotnet/framework/.gitignore
new file mode 100644
index 00000000..76d0819f
--- /dev/null
+++ b/dotnet/framework/.gitignore
@@ -0,0 +1,185 @@
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+
+[Dd]ebug/
+[Rr]elease/
+x64/
+build/
+[Bb]in/
+[Oo]bj/
+
+# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
+!packages/*/build/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+*_i.c
+*_p.c
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.log
+*.scc
+
+# OS generated files #
+.DS_Store*
+ehthumbs.db
+Icon?
+Thumbs.db
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+*.cachefile
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+*.ncrunch*
+.*crunch*.local.xml
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.Publish.xml
+
+# NuGet Packages Directory
+## TODO: If you have NuGet Package Restore enabled, uncomment the next line
+packages/
+
+# Windows Azure Build Output
+csx
+*.build.csdef
+
+# Windows Store app package directory
+AppPackages/
+
+# Others
+sql/
+*.Cache
+ClientBin/
+[Ss]tyle[Cc]op.*
+~$*
+*~
+*.dbmdl
+*.[Pp]ublish.xml
+*.pfx
+*.publishsettings
+modulesbin/
+tempbin/
+
+# EPiServer Site file (VPP)
+AppData/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# vim
+*.txt~
+*.swp
+*.swo
+
+# svn
+.svn
+
+# SQL Server files
+**/App_Data/*.mdf
+**/App_Data/*.ldf
+**/App_Data/*.sdf
+
+
+#LightSwitch generated files
+GeneratedArtifacts/
+_Pvt_Extensions/
+ModelManifest.xml
+
+# =========================
+# Windows detritus
+# =========================
+
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Mac desktop service store files
+.DS_Store
+
+# SASS Compiler cache
+.sass-cache
+
+# Visual Studio 2014 CTP
+**/*.sln.ide
+
+# OpenICF
+**/version.txt
+**/AssemblyInfo.cs
+Dist/
+FrameworkProtoBuf/*.cs
diff --git a/dotnet/framework/BooScriptExecutorFactory/BooScriptExecutorFactory.cs b/dotnet/framework/BooScriptExecutorFactory/BooScriptExecutorFactory.cs
new file mode 100644
index 00000000..eb34b10d
--- /dev/null
+++ b/dotnet/framework/BooScriptExecutorFactory/BooScriptExecutorFactory.cs
@@ -0,0 +1,89 @@
+/*
+ * ====================
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License("CDDL") (the "License"). You may not use this file
+ * except in compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://opensource.org/licenses/cddl1.php
+ * See the License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * When distributing the Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://opensource.org/licenses/cddl1.php.
+ * If applicable, add the following below this CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ * ====================
+ * Portions Copyrighted 2014 ForgeRock AS.
+ */
+
+using System.Reflection;
+using System.Collections.Generic;
+using Boo.Lang.Interpreter;
+using Boo.Lang.Compiler;
+
+namespace Org.IdentityConnectors.Common.Script.Boo
+{
+ [ScriptExecutorFactoryClass("Boo")]
+ public class BooScriptExecutorFactory : ScriptExecutorFactory
+ {
+ ///
+ /// Attempt to trigger an exception if the runtime is not present.
+ ///
+ public BooScriptExecutorFactory()
+ {
+ new BooScriptExecutor(new Assembly[0], "1").Execute(null);
+ }
+
+ ///
+ /// Creates a script executor give the Boo script.
+ ///
+ override
+ public ScriptExecutor NewScriptExecutor(Assembly[] referencedAssemblies, string script, bool compile)
+ {
+ return new BooScriptExecutor(referencedAssemblies, script);
+ }
+
+ ///
+ /// Processes the script.
+ ///
+ class BooScriptExecutor : ScriptExecutor
+ {
+ private readonly Assembly[] _referencedAssemblies;
+ private readonly string _script;
+ private readonly InteractiveInterpreter _engine;
+
+ public BooScriptExecutor(Assembly[] referencedAssemblies, string script)
+ {
+ _referencedAssemblies = referencedAssemblies;
+ _script = script;
+ _engine = new InteractiveInterpreter();
+ _engine.RememberLastValue = true;
+ foreach (Assembly assembly in referencedAssemblies)
+ {
+ _engine.References.Add(assembly);
+ }
+ }
+ public object Execute(IDictionary arguments)
+ {
+ // add all the globals
+ IDictionary args = CollectionUtil.NullAsEmpty(arguments);
+ foreach (KeyValuePair entry in args)
+ {
+ _engine.SetValue(entry.Key, entry.Value);
+ }
+ CompilerContext context = _engine.Eval(_script);
+ if (context.Errors.Count > 0)
+ {
+ throw context.Errors[0];
+ }
+ return _engine.LastValue;
+ }
+ }
+ }
+}
diff --git a/dotnet/framework/BooScriptExecutorFactory/BooScriptExecutorFactory.csproj b/dotnet/framework/BooScriptExecutorFactory/BooScriptExecutorFactory.csproj
new file mode 100644
index 00000000..d7bddd6f
--- /dev/null
+++ b/dotnet/framework/BooScriptExecutorFactory/BooScriptExecutorFactory.csproj
@@ -0,0 +1,100 @@
+
+
+
+
+ {0747C440-70E4-4E63-9F9D-03B3A010C991}
+ Debug
+ AnyCPU
+ Library
+ Org.IdentityConnectors.Common.Script.Boo
+ Boo.ScriptExecutorFactory
+ Boo ScriptExecutor Factory
+ v4.5.2
+
+
+
+ prompt
+ 4
+ AnyCPU
+ bin\Debug\
+ True
+ Full
+ False
+ True
+ DEBUG;TRACE
+ false
+
+
+ pdbonly
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ AnyCPU
+ true
+ True
+ False
+ false
+
+
+
+ lib\Boo.Lang.dll
+
+
+ lib\Boo.Lang.Compiler.dll
+
+
+ lib\Boo.Lang.Interpreter.dll
+
+
+ lib\Boo.Lang.Parser.dll
+
+
+ lib\Boo.Lang.Useful.dll
+
+
+
+ 4.0
+
+
+
+ 4.0
+
+
+
+
+
+
+
+
+ {F140E8DA-52B4-4159-992A-9DA10EA8EEFB}
+ Common
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dotnet/framework/BooScriptExecutorFactory/lib/Boo.Lang.Compiler.dll b/dotnet/framework/BooScriptExecutorFactory/lib/Boo.Lang.Compiler.dll
new file mode 100644
index 00000000..7a4bc09b
Binary files /dev/null and b/dotnet/framework/BooScriptExecutorFactory/lib/Boo.Lang.Compiler.dll differ
diff --git a/dotnet/framework/BooScriptExecutorFactory/lib/Boo.Lang.Interpreter.dll b/dotnet/framework/BooScriptExecutorFactory/lib/Boo.Lang.Interpreter.dll
new file mode 100644
index 00000000..407d0114
Binary files /dev/null and b/dotnet/framework/BooScriptExecutorFactory/lib/Boo.Lang.Interpreter.dll differ
diff --git a/dotnet/framework/BooScriptExecutorFactory/lib/Boo.Lang.Parser.dll b/dotnet/framework/BooScriptExecutorFactory/lib/Boo.Lang.Parser.dll
new file mode 100644
index 00000000..8bf0313d
Binary files /dev/null and b/dotnet/framework/BooScriptExecutorFactory/lib/Boo.Lang.Parser.dll differ
diff --git a/dotnet/framework/BooScriptExecutorFactory/lib/Boo.Lang.Useful.dll b/dotnet/framework/BooScriptExecutorFactory/lib/Boo.Lang.Useful.dll
new file mode 100644
index 00000000..73b49455
Binary files /dev/null and b/dotnet/framework/BooScriptExecutorFactory/lib/Boo.Lang.Useful.dll differ
diff --git a/dotnet/framework/BooScriptExecutorFactory/lib/Boo.Lang.dll b/dotnet/framework/BooScriptExecutorFactory/lib/Boo.Lang.dll
new file mode 100644
index 00000000..83dc5fbc
Binary files /dev/null and b/dotnet/framework/BooScriptExecutorFactory/lib/Boo.Lang.dll differ
diff --git a/dotnet/framework/BooScriptExecutorFactory/version.template b/dotnet/framework/BooScriptExecutorFactory/version.template
new file mode 100644
index 00000000..c085cfe1
--- /dev/null
+++ b/dotnet/framework/BooScriptExecutorFactory/version.template
@@ -0,0 +1 @@
+1.5.0.0
\ No newline at end of file
diff --git a/dotnet/framework/Common/Assertions.cs b/dotnet/framework/Common/Assertions.cs
new file mode 100644
index 00000000..b9785f2a
--- /dev/null
+++ b/dotnet/framework/Common/Assertions.cs
@@ -0,0 +1,114 @@
+/*
+ * ====================
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License("CDDL") (the "License"). You may not use this file
+ * except in compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://opensource.org/licenses/cddl1.php
+ * See the License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * When distributing the Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://opensource.org/licenses/cddl1.php.
+ * If applicable, add the following below this CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ * ====================
+ * Portions Copyrighted 2014 ForgeRock AS.
+ */
+using System;
+using System.Diagnostics;
+
+namespace Org.IdentityConnectors.Common
+{
+ ///
+ /// Description of Assertions.
+ ///
+ public static class Assertions
+ {
+ private const string NULL_FORMAT = "Parameter '{0}' must not be null.";
+ private const string BLANK_FORMAT = "Parameter '{0}' must not be blank.";
+
+ ///
+ /// Throws if the parameter
+ /// is null
.
+ ///
+ /// check if the object is null
.
+ /// name of the parameter to check for null
.
+ /// if is null
and constructs a
+ /// message with the name of the parameter.
+ public static void NullCheck(Object o, String param)
+ {
+ Debug.Assert(StringUtil.IsNotBlank(param));
+ if (o == null)
+ {
+ throw new ArgumentNullException(String.Format(NULL_FORMAT, param));
+ }
+ }
+
+ ///
+ /// Throws if the parameter
+ /// is null
, otherwise returns its value.
+ ///
+ /// the type of the parameter to check for null
. Must be a reference type.
+ /// check if the object is null
.
+ /// name of the parameter to check for null
.
+ /// the value of the parameter .
+ /// if is null
and constructs a
+ /// message with the name of the parameter.
+ public static T NullChecked(T o, String param) where T : class
+ {
+ // Avoid calling NullCheck() here to reuse code: it deepens the stack trace.
+ // We want the exception to be thrown as close to the call site as possible.
+ Debug.Assert(StringUtil.IsNotBlank(param));
+ if (o == null)
+ {
+ throw new ArgumentNullException(String.Format(NULL_FORMAT, param));
+ }
+ return o;
+ }
+
+ ///
+ /// Throws if the parameter
+ /// is null
or blank.
+ ///
+ /// value to test for blank.
+ /// name of the parameter to check.
+ /// if is null
or blank and constructs a
+ /// message with the name of the parameter.
+ public static void BlankCheck(String o, String param)
+ {
+ Debug.Assert(StringUtil.IsNotBlank(param));
+ if (StringUtil.IsBlank(o))
+ {
+ throw new ArgumentException(String.Format(BLANK_FORMAT, param));
+ }
+ }
+
+ ///
+ /// Throws if the parameter
+ /// is null
or blank, otherwise returns its value.
+ ///
+ /// value to test for blank.
+ /// name of the parameter to check.
+ /// the value of the parameter .
+ /// if is null
or blank and constructs a
+ /// message with the name of the parameter.
+ public static String BlankChecked(String o, String param)
+ {
+ // Avoid calling BlankCheck() here to reuse code: it deepens the stack trace.
+ // We want the exception to be thrown as close to the call site as possible.
+ Debug.Assert(StringUtil.IsNotBlank(param));
+ if (StringUtil.IsBlank(o))
+ {
+ throw new ArgumentException(String.Format(BLANK_FORMAT, param));
+ }
+ return o;
+ }
+ }
+}
diff --git a/dotnet/framework/Common/AsyncHandler.cs b/dotnet/framework/Common/AsyncHandler.cs
new file mode 100755
index 00000000..397dfc9a
--- /dev/null
+++ b/dotnet/framework/Common/AsyncHandler.cs
@@ -0,0 +1,58 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2015 ForgeRock AS. All rights reserved.
+ *
+ * The contents of this file are subject to the terms
+ * of the Common Development and Distribution License
+ * (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://forgerock.org/license/CDDLv1.0.html
+ * See the License for the specific language governing
+ * permission and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL
+ * Header Notice in each file and include the License file
+ * at http://forgerock.org/license/CDDLv1.0.html
+ * If applicable, add the following below the CDDL Header,
+ * with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ */
+
+namespace Org.IdentityConnectors.Common
+{
+ ///
+ /// A completion handler for consuming errors which occur during the execution of
+ /// asynchronous tasks.
+ ///
+ ///
+ /// The type of error consumed by the handler.
+ public interface IFailureHandler
+ {
+ ///
+ /// Invoked when the asynchronous task has failed.
+ ///
+ ///
+ /// The error indicating why the asynchronous task has failed.
+ void HandleError(TE error);
+ }
+
+ ///
+ /// A completion handler for consuming the results of asynchronous tasks.
+ ///
+ ///
+ /// The type of result consumed by the handler.
+ public interface ISuccessHandler
+ {
+ ///
+ /// Invoked when the asynchronous task has completed successfully.
+ ///
+ ///
+ /// The result of the asynchronous task.
+ void HandleResult(TV result);
+ }
+
+}
\ No newline at end of file
diff --git a/dotnet/framework/Common/CollectionUtil.cs b/dotnet/framework/Common/CollectionUtil.cs
new file mode 100644
index 00000000..941d973a
--- /dev/null
+++ b/dotnet/framework/Common/CollectionUtil.cs
@@ -0,0 +1,1185 @@
+/*
+ * ====================
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License("CDDL") (the "License"). You may not use this file
+ * except in compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://opensource.org/licenses/cddl1.php
+ * See the License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * When distributing the Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://opensource.org/licenses/cddl1.php.
+ * If applicable, add the following below this CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ * ====================
+ * Portions Copyrighted 2015 ForgeRock AS.
+ */
+using System;
+using System.Runtime.CompilerServices;
+using System.Reflection;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Org.IdentityConnectors.Common
+{
+ internal class IdentityEqualityComparer : IEqualityComparer where T : class
+ {
+ public bool Equals(T x, T y)
+ {
+ return Object.ReferenceEquals(x, y);
+ }
+ public int GetHashCode(T o)
+ {
+ return RuntimeHelpers.GetHashCode(o);
+ }
+ }
+
+ internal class ReadOnlyCollection : ICollection
+ {
+ private readonly ICollection _target;
+ public ReadOnlyCollection(ICollection target)
+ {
+ _target = target;
+ }
+ public void Add(T item)
+ {
+ throw new NotSupportedException();
+ }
+ public void Clear()
+ {
+ throw new NotSupportedException();
+ }
+ public bool Contains(T item)
+ {
+ return _target.Contains(item);
+ }
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ return _target.GetEnumerator();
+ }
+ public IEnumerator GetEnumerator()
+ {
+ return _target.GetEnumerator();
+ }
+ public bool IsReadOnly
+ {
+ get
+ {
+ return true;
+ }
+ }
+ public int Count
+ {
+ get
+ {
+ return _target.Count;
+ }
+ }
+ public bool Remove(T item)
+ {
+ throw new NotSupportedException();
+ }
+ public void CopyTo(T[] array,
+ int arrayIndex)
+ {
+ _target.CopyTo(array, arrayIndex);
+ }
+
+ public ICollection GetTarget()
+ {
+ return _target;
+ }
+
+ }
+
+
+ internal class ReadOnlyList : ReadOnlyCollection, IList
+ {
+
+ public ReadOnlyList(IList target)
+ : base(target)
+ {
+
+ }
+ public int IndexOf(T item)
+ {
+ return GetTarget().IndexOf(item);
+ }
+ public void Insert(int index, T item)
+ {
+ throw new NotSupportedException();
+ }
+ public void RemoveAt(int index)
+ {
+ throw new NotSupportedException();
+ }
+
+ public T this[int index]
+ {
+ get
+ {
+ return GetTarget()[index];
+ }
+ set
+ {
+ throw new NotSupportedException();
+ }
+ }
+
+ protected new IList GetTarget()
+ {
+ return (IList)base.GetTarget();
+ }
+ }
+
+ internal class ReadOnlyDictionary :
+ ReadOnlyCollection>,
+ IDictionary
+ {
+ public ReadOnlyDictionary(IDictionary target)
+ : base(target)
+ {
+
+ }
+ public void Add(TKey key, TValue val)
+ {
+ throw new NotSupportedException();
+ }
+ protected new IDictionary GetTarget()
+ {
+ return (IDictionary)base.GetTarget();
+ }
+ public ICollection Keys
+ {
+ get
+ {
+ return new ReadOnlyCollection(GetTarget().Keys);
+ }
+ }
+ public ICollection Values
+ {
+ get
+ {
+ return new ReadOnlyCollection(GetTarget().Values);
+ }
+ }
+ public bool Remove(TKey key)
+ {
+ throw new NotSupportedException();
+ }
+ public bool ContainsKey(TKey key)
+ {
+ return GetTarget().ContainsKey(key);
+ }
+ public bool TryGetValue(TKey key, out TValue value)
+ {
+ return GetTarget().TryGetValue(key, out value);
+ }
+ public TValue this[TKey key]
+ {
+ get
+ {
+ return GetTarget()[key];
+ }
+ set
+ {
+ throw new NotSupportedException();
+ }
+ }
+ }
+
+
+
+
+ ///
+ /// Delegate that returns the Key, given a value
+ ///
+ public delegate TKey KeyFunction(TValue value);
+
+
+ ///
+ /// Description of CollectionUtil.
+ ///
+ public static class CollectionUtil
+ {
+ ///
+ /// Creates a case-insensitive set
+ ///
+ /// An empty case-insensitive set
+ public static ICollection NewCaseInsensitiveSet()
+ {
+ HashSet rv = new HashSet(StringComparer.OrdinalIgnoreCase);
+ return rv;
+ }
+
+ ///
+ /// Returns true if the collection is a case-insensitive set
+ ///
+ /// The collection. May be null.
+ /// true if the collection is a case-insensitive set
+ public static bool IsCaseInsensitiveSet(ICollection collection)
+ {
+ if (collection is ReadOnlyCollection)
+ {
+ ReadOnlyCollection roc =
+ (ReadOnlyCollection)collection;
+ return IsCaseInsensitiveSet(roc.GetTarget());
+ }
+ else if (collection is HashSet)
+ {
+ HashSet set = (HashSet)collection;
+ return StringComparer.OrdinalIgnoreCase.Equals(set.Comparer);
+ }
+ else
+ {
+ return false;
+ }
+ }
+ ///
+ /// Creates a case-insensitive map
+ ///
+ /// An empty case-insensitive map
+ public static IDictionary NewCaseInsensitiveDictionary()
+ {
+ Dictionary rv = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ return rv;
+ }
+
+ ///
+ /// Returns true if the collection is a case-insensitive map
+ ///
+ /// The map. May be null.
+ /// true if the collection is a case-insensitive map
+ public static bool IsCaseInsensitiveDictionary(IDictionary map)
+ {
+ if (map is ReadOnlyDictionary)
+ {
+ ReadOnlyDictionary roc =
+ (ReadOnlyDictionary)map;
+ return IsCaseInsensitiveDictionary((IDictionary)roc.GetTarget());
+ }
+ else if (map is Dictionary)
+ {
+ Dictionary d = (Dictionary)map;
+ return StringComparer.OrdinalIgnoreCase.Equals(d.Comparer);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Creates a dictionary where the keys are looked up using
+ /// reference equality
+ ///
+ ///
+ public static IDictionary NewIdentityDictionary()
+ where K : class
+ {
+ IdentityEqualityComparer comp = new IdentityEqualityComparer();
+ return new Dictionary(comp);
+ }
+
+ ///
+ /// Computes a hashCode over the enumeration. The hashCode is computed
+ /// such that it doesn't matter what order the elements are listed in. Thus, it
+ /// is suitable for arrays, lists, sets, and dictionaries
+ ///
+ /// The enumerable
+ /// The hashcode
+ public static int GetEnumerableHashCode(IEnumerable enum1)
+ {
+ if (enum1 == null)
+ {
+ return 0;
+ }
+ int rv = 0;
+ foreach (T val1 in enum1)
+ {
+ unchecked
+ {
+ rv += CollectionUtil.GetHashCode(val1);
+ }
+ }
+ return rv;
+ }
+
+ ///
+ /// Computes a hashCode for a key value pair.
+ ///
+ /// The pair
+ /// The hashcode
+ public static int GetKeyValuePairHashCode(KeyValuePair pair)
+ {
+ int rv = 0;
+ unchecked
+ {
+ rv += CollectionUtil.GetHashCode(pair.Key);
+ rv += CollectionUtil.GetHashCode(pair.Value);
+ }
+ return rv;
+ }
+
+ ///
+ /// Returns true if the two sets contain the same elements. This is only for
+ /// sets and dictionaries. Does not work for Lists or Arrays.
+ ///
+ /// The first collection
+ /// The second collection
+ ///
+ public static bool SetsEqual(ICollection collection1,
+ ICollection collection2)
+ {
+ return SetsEqual(collection1, collection2, false);
+ }
+
+ private static bool _SetsEqual(ICollection collection1,
+ ICollection collection2, Boolean equalsIgnoreCase)
+ {
+ return SetsEqual(collection1, collection2, equalsIgnoreCase);
+ }
+
+ ///
+ /// Returns true if the two sets contain the same elements. This is only for
+ /// sets and dictionaries. Does not work for Lists or Arrays.
+ ///
+ /// The first collection
+ /// The second collection
+ ///
+ ///
+ public static bool SetsEqual(ICollection collection1,
+ ICollection collection2, Boolean equalsIgnoreCase)
+ {
+ if (collection1 == null || collection2 == null)
+ {
+ return collection1 == null && collection2== null;
+ }
+ if (collection1.Count != collection2.Count)
+ {
+ return false;
+ }
+ foreach (T val1 in collection1)
+ {
+ if (!collection2.Contains(val1))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ ///
+ /// Gets the given value from the map or default if not exists. Always
+ /// use this rather than map[] since map[] throws an exception if not
+ /// exists.
+ ///
+ /// The map
+ /// The key
+ /// The default value
+ ///
+ public static TValue GetValue(IDictionary map,
+ TKey key,
+ TValue def)
+ {
+ TValue rv;
+ bool present = map.TryGetValue(key, out rv);
+ if (present)
+ {
+ return rv;
+ }
+ else
+ {
+ return def;
+ }
+ }
+
+ ///
+ /// Adds all the elements from the given enumerable to the given collection.
+ ///
+ /// The collection to add to
+ /// The enumerable to get from
+ public static void AddAll(ICollection collection,
+ IEnumerable enumerable)
+ where U : T
+ {
+ if (enumerable != null)
+ {
+ foreach (U obj in enumerable)
+ {
+ collection.Add(obj);
+ }
+ }
+ }
+
+ ///
+ /// Adds all the elements from the given enumerable to the given collection.
+ /// Replace the element value if already stored in the collection.
+ ///
+ /// IDictionary key type
+ /// IDictionary value type
+ /// Enumeration key type, has to extend IDictionary key type
+ /// Enumeration value type, has to extend IDictionary value type
+ /// The collection to add to
+ /// The enumerable to get from
+ public static void AddOrReplaceAll(IDictionary collection,
+ IEnumerable> enumerable)
+ where UKey : TKey
+ where UValue : TValue
+ {
+ if (enumerable != null)
+ {
+ foreach (KeyValuePair obj in enumerable)
+ {
+ collection[obj.Key] = obj.Value;
+ }
+ }
+ }
+
+ ///
+ /// Adds all the elements from the given enumerable to the given collection.
+ ///
+ /// The collection to add to
+ /// The enumerable to get from
+ public static void RemoveAll(ICollection collection,
+ IEnumerable enumerable)
+ where U : T
+ {
+ if (enumerable != null)
+ {
+ foreach (U obj in enumerable)
+ {
+ collection.Remove(obj);
+ }
+ }
+ }
+
+ ///
+ /// Adds all the elements from the given enumerable to the given collection.
+ ///
+ /// The collection to add to
+ /// The enumerable to get from
+ public static void RemovalAll(ICollection collection,
+ IEnumerable enumerable)
+ where U : T
+ {
+ if (enumerable != null)
+ {
+ foreach (U obj in enumerable)
+ {
+ collection.Remove(obj);
+ }
+ }
+ }
+
+
+ ///
+ /// Returns c or an empty collection if c is null.
+ ///
+ /// The collection
+ /// c or an empty collection if c is null.
+ public static ICollection NullAsEmpty(ICollection c)
+ {
+ return c ?? new HashSet();
+ }
+
+ ///
+ /// Returns c or an empty collection if c is null.
+ ///
+ /// The collection
+ /// c or an empty collection if c is null.
+ public static IDictionary NullAsEmpty(IDictionary c)
+ {
+ return c ?? new Dictionary();
+ }
+
+ ///
+ /// Returns c or an empty collection if c is null.
+ ///
+ /// The collection
+ /// c or an empty collection if c is null.
+ public static IList NullAsEmpty(IList c)
+ {
+ return c ?? new List();
+ }
+
+ ///
+ /// Returns c or an empty array if c is null.
+ ///
+ /// The array
+ /// c or an empty collection if c is null.
+ public static T[] NullAsEmpty(T[] c)
+ {
+ return c ?? new T[0];
+ }
+
+ ///
+ /// Given a collection of values a key function, builds a dictionary
+ ///
+ /// List of values
+ /// Key function, mapping from key to value
+ /// The dictionay
+ public static IDictionary NewDictionary(
+ TKey k0,
+ TValue v0)
+ {
+ IDictionary rv = new Dictionary();
+ rv[k0] = v0;
+ return rv;
+ }
+
+ public static IDictionary NewDictionary(T k0, K v0, T k1, K v1)
+ {
+ IDictionary map = NewDictionary(k0, v0);
+ map[k1] = v1;
+ return map;
+ }
+
+ public static IDictionary NewDictionary(T k0, K v0, T k1, K v1, T k2, K v2)
+ {
+ IDictionary map = NewDictionary(k0, v0, k1, v1);
+ map[k2] = v2;
+ return map;
+ }
+
+ public static IDictionary NewDictionary(T k0, K v0, T k1, K v1, T k2, K v2, T k3, K v3)
+ {
+ IDictionary map = NewDictionary(k0, v0, k1, v1, k2, v2);
+ map[k3] = v3;
+ return map;
+ }
+
+ public static IDictionary NewDictionary(T k0, K v0, T k1, K v1, T k2, K v2, T k3, K v3, T k4, K v4)
+ {
+ IDictionary map = NewDictionary(k0, v0, k1, v1, k2, v2, k3, v3);
+ map[k4] = v4;
+ return map;
+ }
+
+ public static IDictionary NewDictionary(T k0, K v0, T k1, K v1, T k2, K v2, T k3, K v3, T k4, K v4, T k5, K v5)
+ {
+ IDictionary map = NewDictionary(k0, v0, k1, v1, k2, v2, k3, v3, k4, v4);
+ map[k5] = v5;
+ return map;
+ }
+
+ ///
+ /// Given a collection of values a key function, builds a dictionary
+ ///
+ /// List of values
+ /// Key function, mapping from key to value
+ /// The dictionay
+ public static IDictionary NewDictionary(
+ IEnumerable values,
+ KeyFunction keyFunction)
+ {
+ IDictionary rv = new Dictionary();
+ if (values != null)
+ {
+ foreach (TValue value in values)
+ {
+ TKey key = keyFunction(value);
+ //DONT use Add - it throws exceptions if already there
+ rv[key] = value;
+ }
+ }
+ return rv;
+ }
+
+ ///
+ /// Given a collection of values a key function, builds a dictionary
+ ///
+ /// List of values
+ /// Key function, mapping from key to value
+ /// The dictionay
+ public static IDictionary NewReadOnlyDictionary(
+ IEnumerable values,
+ KeyFunction keyFunction)
+ {
+ IDictionary rv =
+ NewDictionary(values, keyFunction);
+ return new ReadOnlyDictionary(rv);
+ }
+
+ ///
+ /// Given a collection of values a key function, builds a dictionary
+ ///
+ /// List of values
+ /// Key function, mapping from key to value
+ /// The dictionay
+ public static IDictionary NewDictionary(
+ IDictionary original)
+ {
+ return NewDictionary(original);
+ }
+
+ ///
+ /// Given a collection of values a key function, builds a dictionary
+ ///
+ /// List of values
+ /// Key function, mapping from key to value
+ /// The dictionay
+ public static IDictionary NewDictionary(
+ IDictionary original)
+ {
+ IDictionary rv = new Dictionary();
+ if (original != null)
+ {
+ foreach (KeyValuePair entry in original)
+ {
+ //DONT use Add - it throws exceptions if already there
+ rv[(TKey2)(object)entry.Key] = (TValue2)(object)entry.Value;
+ }
+ }
+ return rv;
+ }
+
+ ///
+ /// Given a collection of values a key function, builds a dictionary
+ ///
+ /// List of values
+ /// Key function, mapping from key to value
+ /// The dictionay
+ public static IDictionary NewReadOnlyDictionary(
+ IDictionary original)
+ {
+ return NewReadOnlyDictionary(original);
+ }
+
+ ///
+ /// Given a collection of values a key function, builds a dictionary
+ ///
+ /// List of values
+ /// Key function, mapping from key to value
+ /// The dictionay
+ public static IDictionary NewReadOnlyDictionary(
+ IDictionary original)
+ {
+ IDictionary rv = NewDictionary(original);
+ return new ReadOnlyDictionary(rv);
+ }
+
+
+ ///
+ /// Returns a modifiable list, after first copying the collection.
+ ///
+ /// A collection. May be null.
+ /// a modifiable list, after first copying the collection.
+ public static IList NewList(IEnumerable collection)
+ {
+ return NewList(collection);
+ }
+
+ ///
+ /// Returns a modifiable list, after first copying the collection.
+ ///
+ /// A collection. May be null.
+ /// a modifiable list, after first copying the collection.
+ public static IList NewList(IEnumerable collection)
+ {
+ IList rv = new List();
+ if (collection != null)
+ {
+ foreach (T element in collection)
+ {
+ rv.Add((U)(object)element);
+ }
+ }
+ return rv;
+ }
+
+ ///
+ /// Returns a modifiable set, after first copying the collection.
+ ///
+ /// A collection. May be null.
+ /// a modifiable set, after first copying the collection.
+ public static ICollection NewSet(IEnumerable collection)
+ {
+ return NewSet(collection);
+ }
+
+ ///
+ /// Returns a modifiable set, after first copying the array.
+ ///
+ /// An array maybe null.
+ /// a modifiable set, after first copying the array.
+ public static ICollection NewSet(params T[] items)
+ {
+ return NewSet((IEnumerable)items);
+ }
+
+ ///
+ /// Returns a modifiable set, after first copying the collection.
+ ///
+ /// A collection. May be null.
+ /// a modifiable set, after first copying the collection.
+ public static ICollection NewSet(IEnumerable collection)
+ {
+ ICollection rv = new HashSet();
+ if (collection != null)
+ {
+ foreach (T element in collection)
+ {
+ rv.Add((TU)(object)element);
+ }
+ }
+ return rv;
+ }
+
+
+ ///
+ /// Returns an unmodifiable list, after first copying the collection.
+ ///
+ /// A collection. May be null.
+ /// an unmodifiable list, after first copying the collection.
+ public static IList NewReadOnlyList(ICollection collection)
+ {
+ return NewReadOnlyList(collection);
+ }
+
+ ///
+ /// Returns an unmodifiable list, after first copying the collection.
+ ///
+ /// A collection. May be null.
+ /// an unmodifiable list, after first copying the collection.
+ public static IList NewReadOnlyList(ICollection collection)
+ {
+ IList list = NewList(collection);
+ return new ReadOnlyList(list);
+ }
+
+ ///
+ /// Returns an unmodifiable list, after first copying the collection.
+ ///
+ /// A collection. May be null.
+ /// an unmodifiable list, after first copying the collection.
+ public static ICollection NewReadOnlySet(ICollection collection)
+ {
+ return NewReadOnlySet(collection);
+ }
+
+ ///
+ /// Returns an unmodifiable list, after first copying the collection.
+ ///
+ /// A collection. May be null.
+ /// an unmodifiable list, after first copying the collection.
+ private static ICollection NewReadOnlySet(ICollection collection)
+ {
+ ICollection list = NewSet(collection);
+ return new ReadOnlyCollection(list);
+ }
+
+ ///
+ /// Returns an unmodifiable set, backed by the original
+ ///
+ /// A collection. May be null.
+ /// an unmodifiable list, after first copying the collection.
+ public static ICollection AsReadOnlySet(ICollection collection)
+ {
+ ICollection list = NullAsEmpty(collection);
+ return new ReadOnlyCollection(list);
+ }
+
+ ///
+ /// Returns an unmodifiable list, backed by the original
+ ///
+ /// A collection. May be null.
+ /// an unmodifiable list, after first copying the collection.
+ public static IList AsReadOnlyList(IList collection)
+ {
+ IList list = NullAsEmpty(collection);
+ return new ReadOnlyList(list);
+ }
+
+ ///
+ /// Returns an unmodifiable list, backed by the original
+ ///
+ /// A collection. May be null.
+ /// an unmodifiable list, after first copying the collection.
+ public static IDictionary AsReadOnlyDictionary(IDictionary d)
+ {
+ d = NullAsEmpty(d);
+ return new ReadOnlyDictionary(d);
+ }
+
+ ///
+ /// Creates a new read-only list from an array.
+ ///
+ ///
+ ///
+ public static IList NewReadOnlyList(params T[] args)
+ {
+ return NewReadOnlyList(args);
+ }
+
+ ///
+ /// Creates a new read-only list from an array.
+ ///
+ ///
+ ///
+ private static IList NewReadOnlyList(params T[] args)
+ {
+ IList list = CollectionUtil.NewList(args);
+ return new ReadOnlyList(list);
+ }
+
+ ///
+ /// Creates a new read-only set from an array.
+ ///
+ ///
+ ///
+ public static ICollection NewReadOnlySet(params T[] args)
+ {
+ return NewReadOnlySet(args);
+ }
+ ///
+ /// Creates a new read-only set from an array.
+ ///
+ ///
+ ///
+ private static ICollection NewReadOnlySet(params T[] args)
+ {
+ ICollection list = CollectionUtil.NewSet(args);
+ return new ReadOnlyCollection(list);
+ }
+
+ public static bool DictionariesEqual(IDictionary m1,
+ IDictionary m2)
+ {
+ return DictionariesEqual(m1, m2, false);
+ }
+
+ private static bool _DictionariesEqual(IDictionary m1,
+ IDictionary m2, Boolean equalsIgnoreCase)
+ {
+ return DictionariesEqual(m1, m2, equalsIgnoreCase);
+ }
+
+ public static bool DictionariesEqual(IDictionary m1,
+ IDictionary m2, Boolean equalsIgnoreCase)
+ {
+ if (m1.Count != m2.Count)
+ {
+ return false;
+ }
+ foreach (KeyValuePair entry1 in m1)
+ {
+ TK key1 = entry1.Key;
+ TV val1 = entry1.Value;
+ if (!m2.ContainsKey(key1))
+ {
+ return false;
+ }
+ Object val2 = m2[key1];
+ if (!CollectionUtil.Equals(val1, val2, equalsIgnoreCase))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool ListsEqual(IList v1,
+ IList v2)
+ {
+ return ListsEqual(v1, v2, false);
+ }
+
+ private static bool _ListsEqual(IList v1,
+ IList v2, Boolean equalsIgnoreCase)
+ {
+ return ListsEqual(v1, v2, equalsIgnoreCase);
+ }
+
+ public static bool ListsEqual(IList v1,
+ IList v2, Boolean equalsIgnoreCase)
+ {
+ if (v1.Count != v2.Count)
+ {
+ return false;
+ }
+ for (int i = 0; i < v1.Count; i++)
+ {
+ if (!CollectionUtil.Equals(v1[i], v2[i]))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ ///
+ /// Forces the compare of two comparable objects and removes any warnings
+ /// generated by the compiler.
+ ///
+ /// the integer value of o1.compareTo(o2).
+ public static int ForceCompare(object o1, object o2)
+ {
+ IComparable t1 = (IComparable)o1;
+ T t2 = (T)o2;
+ return t1.CompareTo(t2);
+ }
+
+ ///
+ /// hashCode function that properly handles arrays,
+ /// collections, maps, collections of arrays, and maps of arrays.
+ ///
+ /// The object. May be null.
+ /// the hashCode
+ public static int GetHashCode(Object o)
+ {
+ if (o == null)
+ {
+ return 0;
+ }
+ else if (o is Array)
+ {
+ Array array = (Array)o;
+ int length = array.Length;
+ int rv = 0;
+ for (int i = 0; i < length; i++)
+ {
+ Object el = array.GetValue(i);
+ unchecked
+ {
+ rv += GetHashCode(el);
+ }
+ }
+ return rv;
+ }
+ else if (ReflectionUtil.IsParentTypeOf(typeof(KeyValuePair<,>), o.GetType()))
+ {
+ Type parent = ReflectionUtil.FindInHierarchyOf(typeof(KeyValuePair<,>), o.GetType());
+ Type[] genericArguments =
+ parent.GetGenericArguments();
+
+ Type collectionUtil = typeof(CollectionUtil);
+ MethodInfo info = collectionUtil.GetMethod("GetKeyValuePairHashCode");
+
+ info = info.MakeGenericMethod(genericArguments);
+
+ Object rv = info.Invoke(null, new object[] { o });
+ return (int)rv;
+ }
+ else if (ReflectionUtil.IsParentTypeOf(typeof(ICollection<>), o.GetType()))
+ {
+ Type parent = ReflectionUtil.FindInHierarchyOf(typeof(ICollection<>), o.GetType());
+
+ Type[] genericArguments =
+ parent.GetGenericArguments();
+
+
+ Type collectionUtil = typeof(CollectionUtil);
+ MethodInfo info = collectionUtil.GetMethod("GetEnumerableHashCode");
+
+ info = info.MakeGenericMethod(genericArguments);
+
+ Object rv = info.Invoke(null, new object[] { o });
+ return (int)rv;
+ }
+ else
+ {
+ return o.GetHashCode();
+ }
+ }
+
+ ///
+ /// Equality function that properly handles arrays,
+ /// lists, maps, lists of arrays, and maps of arrays.
+ ///
+ ///
+ ///
+ /// NOTE: For Sets, this relies on the equals method
+ /// of the Set to do the right thing. This is a reasonable
+ /// assumption since, in order for Sets to behave
+ /// properly as Sets, their values must already have
+ /// a proper implementation of equals. (Or they must
+ /// be specialized Sets that define a custom comparator that
+ /// knows how to do the right thing). The same holds true for Map keys.
+ /// Map values, on the other hand, are compared (so Map values
+ /// can be arrays).
+ ///
+ ///
+ /// The first object. May be null.
+ /// The second object. May be null.
+ /// true if the two objects are equal.
+ public new static bool Equals(Object o1, Object o2)
+ {
+ return Equals(o1, o2, false);
+ }
+
+
+ ///
+ /// Equality function that properly handles arrays,
+ /// lists, maps, lists of arrays, and maps of arrays.
+ ///
+ ///
+ ///
+ /// NOTE: For Sets, this relies on the equals method
+ /// of the Set to do the right thing. This is a reasonable
+ /// assumption since, in order for Sets to behave
+ /// properly as Sets, their values must already have
+ /// a proper implementation of equals. (Or they must
+ /// be specialized Sets that define a custom comparator that
+ /// knows how to do the right thing). The same holds true for Map keys.
+ /// Map values, on the other hand, are compared (so Map values
+ /// can be arrays).
+ ///
+ ///
+ /// The first object. May be null.
+ /// The second object. May be null.
+ /// If true the String and Character comparison is case-ignore
+ /// true if the two objects are equal.
+ public static bool Equals(Object o1, Object o2, Boolean equalsIgnoreCase)
+ {
+ if (o1 == o2)
+ { //same object or both null
+ return true;
+ }
+ else if (o1 == null)
+ {
+ return false;
+ }
+ else if (o2 == null)
+ {
+ return false;
+ }
+ else if (o1 is Array)
+ {
+ Type clazz1 = o1.GetType();
+ Type clazz2 = o2.GetType();
+ if (!clazz1.Equals(clazz2))
+ {
+ return false;
+ }
+ Array array1 = (Array)o1;
+ Array array2 = (Array)o2;
+ int length1 = array1.Length;
+ int length2 = array2.Length;
+ if (length1 != length2)
+ {
+ return false;
+ }
+ for (int i = 0; i < length1; i++)
+ {
+ Object el1 = array1.GetValue(i);
+ Object el2 = array2.GetValue(i);
+ if (!Equals(el1, el2, equalsIgnoreCase))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ else if (ReflectionUtil.IsParentTypeOf(typeof(IList<>), o1.GetType()))
+ {
+ Type parent1 = ReflectionUtil.FindInHierarchyOf(typeof(IList<>), o1.GetType());
+ Type parent2 = ReflectionUtil.FindInHierarchyOf(typeof(IList<>), o2.GetType());
+ if (!parent1.Equals(parent2))
+ {
+ return false;
+ }
+ Type[] genericArguments =
+ parent1.GetGenericArguments();
+
+
+ Type collectionUtil = typeof(CollectionUtil);
+ MethodInfo info = collectionUtil.GetMethod("_ListsEqual", BindingFlags.Static | BindingFlags.NonPublic);
+
+ info = info.MakeGenericMethod(genericArguments);
+
+ Object rv = info.Invoke(null, new object[] { o1, o2, equalsIgnoreCase });
+ return (bool)rv;
+ }
+ else if (ReflectionUtil.IsParentTypeOf(typeof(IDictionary<,>), o1.GetType()))
+ {
+ Type parent1 = ReflectionUtil.FindInHierarchyOf(typeof(IDictionary<,>), o1.GetType());
+ Type parent2 = ReflectionUtil.FindInHierarchyOf(typeof(IDictionary<,>), o2.GetType());
+ if (!parent1.Equals(parent2))
+ {
+ return false;
+ }
+ Type[] genericArguments =
+ parent1.GetGenericArguments();
+
+
+ Type collectionUtil = typeof(CollectionUtil);
+ MethodInfo info = collectionUtil.GetMethod("_DictionariesEqual", BindingFlags.Static | BindingFlags.NonPublic);
+
+ info = info.MakeGenericMethod(genericArguments);
+
+ Object rv = info.Invoke(null, new object[] { o1, o2 , equalsIgnoreCase});
+ return (bool)rv;
+ }
+ else if (ReflectionUtil.IsParentTypeOf(typeof(ICollection<>), o1.GetType()))
+ {
+ Type parent1 = ReflectionUtil.FindInHierarchyOf(typeof(ICollection<>), o1.GetType());
+ Type parent2 = ReflectionUtil.FindInHierarchyOf(typeof(ICollection<>), o2.GetType());
+ if (!parent1.Equals(parent2))
+ {
+ return false;
+ }
+ Type[] genericArguments =
+ parent1.GetGenericArguments();
+
+
+ Type collectionUtil = typeof(CollectionUtil);
+ MethodInfo info = collectionUtil.GetMethod("_SetsEqual", BindingFlags.Static | BindingFlags.NonPublic);
+
+ info = info.MakeGenericMethod(genericArguments);
+
+ Object rv = info.Invoke(null, new object[] { o1, o2, equalsIgnoreCase });
+ return (bool)rv;
+ }
+ else if (equalsIgnoreCase && o1 is string && o2 is string)
+ {
+ return ((string)o1).Equals((string)o2, StringComparison.CurrentCultureIgnoreCase);
+ }
+ else if (equalsIgnoreCase && o1 is char && o2 is char)
+ {
+ return char.ToLower((char)o1) == char.ToLower((char)o2);
+ }
+ else
+ {
+ return o1.Equals(o2);
+ }
+ }
+
+ public static string Dump(ICollection list)
+ {
+ StringBuilder sb = new StringBuilder();
+ if (list != null)
+ {
+ bool first = true;
+ foreach (object o in list)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ sb.Append(", ");
+ }
+ sb.Append(o);
+ }
+ }
+ else
+ {
+ sb.Append("(null)");
+ }
+ return sb.ToString();
+ }
+
+
+ }
+
+}
diff --git a/dotnet/framework/Common/Common.csproj b/dotnet/framework/Common/Common.csproj
new file mode 100644
index 00000000..955da625
--- /dev/null
+++ b/dotnet/framework/Common/Common.csproj
@@ -0,0 +1,109 @@
+
+
+
+
+ {F140E8DA-52B4-4159-992A-9DA10EA8EEFB}
+ Debug
+ AnyCPU
+ Library
+ Org.IdentityConnectors.Common
+ Common
+ Open Connectors Common
+ v4.5.2
+ True
+ False
+ 4
+ false
+ true
+
+
+
+ bin\Debug\
+ true
+ Full
+ False
+ True
+ DEBUG;TRACE
+
+
+ bin\Release\
+ true
+ pdbonly
+ True
+ False
+ TRACE
+
+
+ False
+ Auto
+ 4194304
+ AnyCPU
+ 4096
+
+
+ false
+
+
+ false
+
+
+
+
+
+ 4.0
+
+
+
+ 4.0
+
+
+
+ 4.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dotnet/framework/Common/DateTimeUtil.cs b/dotnet/framework/Common/DateTimeUtil.cs
new file mode 100644
index 00000000..15b934fd
--- /dev/null
+++ b/dotnet/framework/Common/DateTimeUtil.cs
@@ -0,0 +1,54 @@
+/*
+ * ====================
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License("CDDL") (the "License"). You may not use this file
+ * except in compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://opensource.org/licenses/cddl1.php
+ * See the License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * When distributing the Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://opensource.org/licenses/cddl1.php.
+ * If applicable, add the following below this CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ * ====================
+ */
+using System;
+
+namespace Org.IdentityConnectors.Common
+{
+ ///
+ /// Description of DateTimeUtil.
+ ///
+ public static class DateTimeUtil
+ {
+ private static readonly DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc);
+
+ public static DateTime GetDateTimeFromUtcMillis(long dateTime)
+ {
+ return DateTime.FromFileTimeUtc(dateTime * 10000);
+ }
+
+ public static long GetUtcTimeMillis(DateTime dateTime)
+ {
+ return dateTime.ToFileTimeUtc() / 10000;
+ }
+
+ public static long GetCurrentUtcTimeMillis()
+ {
+ return GetUtcTimeMillis(DateTime.Now);
+ }
+
+ public static long GetCurrentUnixTimeMillis()
+ {
+ return (long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds;
+ }
+ }
+}
diff --git a/dotnet/framework/Common/FrameworkInternalBridge.cs b/dotnet/framework/Common/FrameworkInternalBridge.cs
new file mode 100644
index 00000000..7f64841e
--- /dev/null
+++ b/dotnet/framework/Common/FrameworkInternalBridge.cs
@@ -0,0 +1,58 @@
+/*
+ * ====================
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License("CDDL") (the "License"). You may not use this file
+ * except in compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://opensource.org/licenses/cddl1.php
+ * See the License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * When distributing the Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://opensource.org/licenses/cddl1.php.
+ * If applicable, add the following below this CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ * ====================
+ */
+using System;
+using System.Reflection;
+namespace Org.IdentityConnectors.Common
+{
+ ///
+ /// Description of FrameworkInternalBridge.
+ ///
+ internal static class FrameworkInternalBridge
+ {
+ private static readonly Object LOCK = new Object();
+ private static Assembly _assembly = null;
+ ///
+ /// Loads a class from the FrameworkInternal module
+ ///
+ ///
+ ///
+ public static Type LoadType(String typeName)
+ {
+
+ Assembly assembly;
+ lock (LOCK)
+ {
+ if (_assembly == null)
+ {
+ AssemblyName assemName = new AssemblyName();
+ assemName.Name = "FrameworkInternal";
+ _assembly = Assembly.Load(assemName);
+ }
+ assembly = _assembly;
+ }
+
+ return assembly.GetType(typeName, true);
+
+ }
+ }
+}
diff --git a/dotnet/framework/Common/IOUtil.cs b/dotnet/framework/Common/IOUtil.cs
new file mode 100644
index 00000000..7d35aa10
--- /dev/null
+++ b/dotnet/framework/Common/IOUtil.cs
@@ -0,0 +1,446 @@
+/*
+ * ====================
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License("CDDL") (the "License"). You may not use this file
+ * except in compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://opensource.org/licenses/cddl1.php
+ * See the License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * When distributing the Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://opensource.org/licenses/cddl1.php.
+ * If applicable, add the following below this CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ * ====================
+ * Portions Copyrighted 2014 ForgeRock AS.
+ */
+using System;
+using System.Net;
+using System.Collections.Generic;
+using System.Text;
+using System.Diagnostics;
+using System.IO;
+using System.Data.SqlClient;
+using System.Reflection;
+
+namespace Org.IdentityConnectors.Common
+{
+ #region IOUtil
+ ///
+ /// Description of IOUtil.
+ ///
+ public static class IOUtil
+ {
+ ///
+ /// Given an ip address or host, returns the
+ /// IPAddress
+ ///
+ ///
+ ///
+ public static IPAddress GetIPAddress(String hostOrIp)
+ {
+ if (hostOrIp.Equals("0.0.0.0") ||
+ hostOrIp.Equals("::0"))
+ {
+ return IPAddress.Parse(hostOrIp);
+ }
+ return Dns.GetHostAddresses(hostOrIp)[0];
+ }
+
+ ///
+ /// Quietly closes the reader.
+ ///
+ /// This avoids having to handle exceptions, and then inside of the exception
+ /// handling have a try catch block to close the reader and catch any
+ /// which may be thrown and ignore it.
+ ///
+ ///
+ /// Reader to close
+ public static void QuietClose(TextReader reader)
+ {
+ try
+ {
+ if (reader != null)
+ {
+ reader.Close();
+ }
+ }
+ catch (IOException)
+ {
+ // ignore
+ }
+ }
+
+ ///
+ /// Quietly closes the writer.
+ ///
+ /// This avoids having to handle exceptions, and then inside of the exception
+ /// handling have a try catch block to close the Writer and catch any
+ /// which may be thrown.
+ ///
+ ///
+ /// Writer to close
+ public static void QuietClose(TextWriter writer)
+ {
+ try
+ {
+ if (writer != null)
+ {
+ writer.Close();
+ }
+ }
+ catch (IOException)
+ {
+ // ignore
+ }
+ }
+
+ ///
+ /// Quietly closes the stream.
+ ///
+ /// This avoids having to handle exceptions, and then inside of the exception
+ /// handling have a try catch block to close the stream and catch any
+ /// which may be thrown.
+ ///
+ ///
+ /// Stream to close
+ public static void QuietClose(Stream stream)
+ {
+ try
+ {
+ if (stream != null)
+ {
+ stream.Close();
+ }
+ }
+ catch (IOException)
+ {
+ // ignore
+ }
+ }
+
+ ///
+ /// Quietly dispose the statement.
+ ///
+ /// This avoids having to handle exceptions, and then inside of the exception
+ /// handling have a try catch block to close the statement and catch any
+ /// which may be thrown.
+ ///
+ ///
+ /// Statement to dispose
+ /// Since 1.3
+ public static void QuietClose(SqlCommand stmt)
+ {
+ try
+ {
+ if (stmt != null)
+ {
+ stmt.Dispose();
+ }
+ }
+ catch (SqlException)
+ {
+ // ignore
+ }
+ }
+
+ ///
+ /// Quietly closes the connection.
+ ///
+ /// This avoids having to handle exceptions, and then inside of the exception
+ /// handling have a try catch block to close the connection and catch any
+ /// which may be thrown.
+ ///
+ ///
+ /// Connection to close
+ /// Since 1.3
+ public static void QuietClose(SqlConnection conn)
+ {
+ try
+ {
+ if (conn != null)
+ {
+ conn.Close();
+ }
+ }
+ catch (SqlException)
+ {
+ // ignore
+ }
+ }
+
+ ///
+ /// Quietly closes the resultset.
+ ///
+ /// This avoids having to handle exceptions, and then inside of the exception
+ /// handling have a try catch block to close the connection and catch any
+ /// which may be thrown.
+ ///
+ ///
+ /// ResultSet to close
+ /// Since 1.3
+ public static void QuietClose(SqlDataReader resultset)
+ {
+ try
+ {
+ if (resultset != null)
+ {
+ resultset.Close();
+ }
+ }
+ catch (SqlException)
+ {
+ // ignore
+ }
+ }
+
+ // =======================================================================
+ // Resource Utility Methods
+ // =======================================================================
+ ///
+ /// Returns an Assembly contains the typeName.
+ ///
+ ///
+ /// Returns an Assembly or null if not found
+ public static Assembly GetAssemblyContainingType(String typeName)
+ {
+ foreach (Assembly currentassembly in AppDomain.CurrentDomain.GetAssemblies())
+ {
+ Type t = currentassembly.GetType(typeName, false, true);
+ if (t != null)
+ {
+ return currentassembly;
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// Returns an input stream of the resource specified.
+ ///
+ ///
+ ///
+ /// Returns an InputStream to the resource.
+ public static Stream GetResourceAsStream(Type clazz, string resourceName)
+ {
+ Debug.Assert(clazz != null && StringUtil.IsNotBlank(resourceName));
+ return clazz.Assembly.GetManifestResourceStream(resourceName);
+ }
+
+ ///
+ /// Get the resource as a byte array.
+ ///
+ ///
+ ///
+ /// @return
+ public static byte[] GetResourceAsBytes(Type clazz, string res)
+ {
+ Debug.Assert(clazz != null && StringUtil.IsNotBlank(res));
+ // copy bytes from the stream to an array..
+ Stream ins = GetResourceAsStream(clazz, res);
+ if (ins == null)
+ {
+ throw new InvalidOperationException("Resource not found: " + res);
+ }
+
+ byte[] buffer = new byte[16 * 1024];
+ using (MemoryStream ms = new MemoryStream())
+ {
+ int read;
+ while ((read = ins.Read(buffer, 0, buffer.Length)) > 0)
+ {
+ ms.Write(buffer, 0, read);
+ }
+ QuietClose(ins);
+ return ms.ToArray();
+ }
+ }
+
+ ///
+ /// Read the entire stream into a String and return it.
+ ///
+ ///
+ ///
+ ///
+ public static string GetResourceAsString(Type clazz, string res, Encoding charset)
+ {
+ Debug.Assert(clazz != null && StringUtil.IsNotBlank(res));
+ string ret = null;
+ Stream ins = GetResourceAsStream(clazz, res);
+ if (ins != null)
+ {
+ using (StreamReader reader = new StreamReader(ins, charset))
+ {
+ ret = reader.ReadToEnd();
+ }
+ QuietClose(ins);
+ }
+ return ret;
+ }
+
+ ///
+ /// Read the entire stream into a String and return it.
+ ///
+ ///
+ ///
+ ///
+ public static string GetResourceAsString(Type clazz, string res)
+ {
+ Debug.Assert(clazz != null && StringUtil.IsNotBlank(res));
+ return GetResourceAsString(clazz, res, Encoding.UTF8);
+ }
+
+ ///
+ /// Copies a file to a destination.
+ ///
+ ///
+ /// The source must be a file
+ ///
+ /// This can be a directory or a file.
+ /// True if succeeded otherwise false.
+ public static bool CopyFile(String src, String dest)
+ {
+ bool ret = true;
+ // quick exit if this is bogus
+ if (src == null || dest == null || !File.Exists(src))
+ {
+ throw new FileNotFoundException();
+ }
+ // check for directory
+ if (!Directory.Exists(dest))
+ {
+ Directory.CreateDirectory(dest);
+ }
+ File.Copy(src, dest, true);
+ return ret;
+ }
+
+ ///
+ /// Copies one file to another.
+ ///
+ /// NOTE: does not close streams.
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// total bytes copied.
+ public static void CopyFile(Stream input, Stream output)
+ {
+ byte[] buffer = new byte[32768];
+ int read;
+ while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
+ {
+ output.Write(buffer, 0, read);
+ }
+ }
+
+ ///
+ /// Reads the given file as UTF-8
+ ///
+ ///
+ /// The file to read
+ /// The contents of the file
+ ///
+ /// if there is an issue reading the file.
+ public static string ReadFileUTF8(String file)
+ {
+ string content;
+ using (StreamReader reader = new StreamReader(file, Encoding.UTF8))
+ {
+ content = reader.ReadToEnd();
+ }
+ return content;
+ }
+
+ ///
+ /// Write the contents of the string out to a file in UTF-8 format.
+ ///
+ ///
+ /// the file to write to.
+ ///
+ /// the contents of the file to write to.
+ ///
+ /// if there is an issue writing the file.
+ ///
+ /// if the file parameter is null.
+ public static void WriteFileUTF8(String file, string contents)
+ {
+ using (var sw = new StreamWriter(File.Open(file, FileMode.CreateNew), Encoding.UTF8))
+ {
+ sw.WriteLine(contents);
+ }
+ }
+
+ ///
+ ///
+ ///
+ /// Since 1.3
+ public static string Join(ICollection collection, char separator)
+ {
+ if (collection == null)
+ {
+ return null;
+ }
+
+ return Join(new List(collection).ToArray(), separator, 0, collection.Count);
+ }
+
+ ///
+ ///
+ ///
+ /// Since 1.3
+ public static string Join(object[] array, char separator)
+ {
+ if (array == null)
+ {
+ return null;
+ }
+
+ return Join(array, separator, 0, array.Length);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Since 1.3
+ public static string Join(object[] array, char separator, int startIndex, int endIndex)
+ {
+ if (array == null)
+ {
+ return null;
+ }
+ int noOfItems = endIndex - startIndex;
+ if (noOfItems <= 0)
+ {
+ return String.Empty;
+ }
+
+ StringBuilder buf = new StringBuilder(noOfItems * 16);
+
+ for (int i = startIndex; i < endIndex; i++)
+ {
+ if (i > startIndex)
+ {
+ buf.Append(separator);
+ }
+ if (array[i] != null)
+ {
+ buf.Append(array[i]);
+ }
+ }
+ return buf.ToString();
+ }
+ }
+ #endregion
+}
diff --git a/dotnet/framework/Common/Locale.cs b/dotnet/framework/Common/Locale.cs
new file mode 100644
index 00000000..342b515e
--- /dev/null
+++ b/dotnet/framework/Common/Locale.cs
@@ -0,0 +1,240 @@
+/*
+ * ====================
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License("CDDL") (the "License"). You may not use this file
+ * except in compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://opensource.org/licenses/cddl1.php
+ * See the License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * When distributing the Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://opensource.org/licenses/cddl1.php.
+ * If applicable, add the following below this CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ * ====================
+ */
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+namespace Org.IdentityConnectors.Common
+{
+ ///
+ /// Represents a Java Locale and has facilities for converting to/from
+ /// C# CultureInfo
+ ///
+ public sealed class Locale
+ {
+ private static readonly IDictionary
+ Locale2CultureInfoName = new Dictionary();
+ private static readonly IDictionary
+ CultureInfoName2Locale = new Dictionary();
+
+ private static void AddMapping(Locale locale, String name)
+ {
+ Locale2CultureInfoName[locale] = name;
+ CultureInfoName2Locale[name] = locale;
+ }
+
+ ///