From 4534ad5122af1c6b89482da7c2331c7a9cd73844 Mon Sep 17 00:00:00 2001 From: abadea Date: Fri, 13 Nov 2009 10:56:39 +0000 Subject: [PATCH 01/33] Issue 593: Move framework to a single directory - .NET part --- .../ActiveDirectoryConnector.csproj | 38 +- .../ActiveDirectoryConnectorTests.csproj | 44 +- .../BooScriptExecutorFactory.cs | 89 - .../BooScriptExecutorFactory.csproj | 96 - .../lib/Boo.Lang.Compiler.dll | Bin 729088 -> 0 bytes .../lib/Boo.Lang.Interpreter.dll | Bin 86016 -> 0 bytes .../lib/Boo.Lang.Parser.dll | Bin 421888 -> 0 bytes .../lib/Boo.Lang.Useful.dll | Bin 81920 -> 0 bytes BooScriptExecutorFactory/lib/Boo.Lang.dll | Bin 110592 -> 0 bytes BooScriptExecutorFactory/version.template | 1 - Common/Assertions.cs | 66 - Common/CollectionUtil.cs | 1030 ---- Common/Common.csproj | 95 - Common/DateTimeUtil.cs | 47 - Common/FrameworkInternalBridge.cs | 58 - Common/IOUtil.cs | 48 - Common/Locale.cs | 240 - Common/Pair.cs | 75 - Common/Pooling.cs | 233 - Common/Proxy.cs | 272 - Common/ReflectionUtil.cs | 171 - Common/SafeType.cs | 144 - Common/Script.cs | 182 - Common/Security.cs | 876 --- Common/StringUtil.cs | 97 - Common/TraceUtil.cs | 52 - Common/XmlUtil.cs | 225 - Common/version.template | 1 - Console/Console.csproj | 91 - Console/MainForm.Designer.cs | 47 - Console/MainForm.cs | 47 - Console/Program.cs | 45 - Console/version.template | 1 - DotNetConnectors.sln | 73 - ExchangeConnector/ExchangeConnector.csproj | 21 +- Framework/Api.cs | 592 -- Framework/ApiOperations.cs | 470 -- Framework/Common.cs | 382 -- Framework/CommonExceptions.cs | 392 -- Framework/CommonObjects.cs | 4849 ----------------- Framework/CommonObjectsFilter.cs | 1471 ----- Framework/CommonSerializer.cs | 305 -- Framework/Framework.csproj | 99 - Framework/Spi.cs | 340 -- Framework/SpiOperations.cs | 492 -- Framework/version.template | 1 - FrameworkInternal/Api.cs | 988 ---- FrameworkInternal/ApiLocal.cs | 1194 ---- FrameworkInternal/ApiLocalOperations.cs | 1613 ------ FrameworkInternal/ApiRemote.cs | 428 -- FrameworkInternal/ApiRemoteMessages.cs | 276 - FrameworkInternal/ExceptionUtil.cs | 87 - FrameworkInternal/FrameworkInternal.csproj | 109 - FrameworkInternal/Resources.resx | 508 -- FrameworkInternal/Security.cs | 138 - FrameworkInternal/Serializer.cs | 2875 ---------- FrameworkInternal/SerializerBinary.cs | 895 --- FrameworkInternal/SerializerXml.cs | 930 ---- FrameworkInternal/Server.cs | 1054 ---- FrameworkInternal/Test.cs | 152 - FrameworkInternal/version.template | 1 - FrameworkTests/CollectionUtilTests.cs | 162 - FrameworkTests/ConnectorAttributeUtilTests.cs | 62 - .../ConnectorFacadeExceptionTests.cs | 124 - FrameworkTests/ConnectorFacadeTests.cs | 415 -- FrameworkTests/ConnectorInfoManagerTests.cs | 623 --- FrameworkTests/ExceptionUtilTests.cs | 117 - FrameworkTests/FilterTranslatorTests.cs | 643 --- FrameworkTests/FrameworkTests.csproj | 172 - FrameworkTests/GuardedByteArrayTests.cs | 105 - FrameworkTests/GuardedStringTests.cs | 107 - FrameworkTests/LocaleTests.cs | 213 - FrameworkTests/MockConnector.cs | 341 -- FrameworkTests/ObjectClassUtilTests.cs | 45 - FrameworkTests/ObjectNormalizerFacadeTests.cs | 251 - FrameworkTests/ObjectPoolTests.cs | 284 - FrameworkTests/ObjectSerializationTests.cs | 1248 ----- .../config/config.xml | 28 - .../config/myconfig/config.xml | 27 - FrameworkTests/PropertyBagTests.cs | 135 - FrameworkTests/ProxyTests.cs | 97 - FrameworkTests/SafeTypeTest.cs | 46 - FrameworkTests/ScriptTests.cs | 147 - FrameworkTests/TestHelperTests.cs | 248 - FrameworkTests/TestUtil.cs | 53 - FrameworkTests/UpdateImplTests.cs | 228 - FrameworkTests/app.config | 24 - FrameworkTests/version.template | 1 - Service/Program.cs | 251 - Service/ProjectInstaller.cs | 56 - Service/Service.cs | 182 - Service/Service.csproj | 114 - Service/app.config | 37 - Service/version.template | 1 - ServiceInstall/ExtBuild.proj | 65 - ServiceInstall/File.bottom | 7 - ServiceInstall/File.top | 22 - ServiceInstall/ServiceInstall.wixproj | 72 - ServiceInstall/Setup.wxs | 50 - ServiceInstall/license.rtf | 30 - .../ShellScriptExecutorFactory.cs | 151 - .../ShellScriptExecutorFactory.csproj | 82 - ShellScriptExecutorFactory/version.template | 1 - TestBundleV1/AssemblyInfo.cs | 57 - TestBundleV1/Messages.es-ES.resx | 126 - TestBundleV1/Messages.es.resx | 126 - TestBundleV1/Messages.resx | 126 - TestBundleV1/TestBundleV1.csproj | 91 - TestBundleV1/TestConnector.cs | 248 - TestBundleV2/AssemblyInfo.cs | 55 - TestBundleV2/TestBundleV2.csproj | 82 - TestBundleV2/TestConnector.cs | 64 - TestCommon/FrameworkInternalBridge.cs | 62 - TestCommon/PropertyBag.cs | 154 - TestCommon/Test.cs | 529 -- TestCommon/TestCommon.csproj | 69 - TestCommon/TestHelpersSpi.cs | 54 - TestCommon/config.xsd | 38 - TestCommon/version.template | 1 - server.pfx | Bin 1704 -> 0 bytes 120 files changed, 55 insertions(+), 34040 deletions(-) delete mode 100644 BooScriptExecutorFactory/BooScriptExecutorFactory.cs delete mode 100644 BooScriptExecutorFactory/BooScriptExecutorFactory.csproj delete mode 100644 BooScriptExecutorFactory/lib/Boo.Lang.Compiler.dll delete mode 100644 BooScriptExecutorFactory/lib/Boo.Lang.Interpreter.dll delete mode 100644 BooScriptExecutorFactory/lib/Boo.Lang.Parser.dll delete mode 100644 BooScriptExecutorFactory/lib/Boo.Lang.Useful.dll delete mode 100644 BooScriptExecutorFactory/lib/Boo.Lang.dll delete mode 100644 BooScriptExecutorFactory/version.template delete mode 100644 Common/Assertions.cs delete mode 100644 Common/CollectionUtil.cs delete mode 100644 Common/Common.csproj delete mode 100644 Common/DateTimeUtil.cs delete mode 100644 Common/FrameworkInternalBridge.cs delete mode 100644 Common/IOUtil.cs delete mode 100644 Common/Locale.cs delete mode 100644 Common/Pair.cs delete mode 100644 Common/Pooling.cs delete mode 100644 Common/Proxy.cs delete mode 100644 Common/ReflectionUtil.cs delete mode 100644 Common/SafeType.cs delete mode 100644 Common/Script.cs delete mode 100644 Common/Security.cs delete mode 100644 Common/StringUtil.cs delete mode 100644 Common/TraceUtil.cs delete mode 100644 Common/XmlUtil.cs delete mode 100644 Common/version.template delete mode 100644 Console/Console.csproj delete mode 100644 Console/MainForm.Designer.cs delete mode 100644 Console/MainForm.cs delete mode 100644 Console/Program.cs delete mode 100644 Console/version.template delete mode 100644 Framework/Api.cs delete mode 100644 Framework/ApiOperations.cs delete mode 100644 Framework/Common.cs delete mode 100644 Framework/CommonExceptions.cs delete mode 100644 Framework/CommonObjects.cs delete mode 100644 Framework/CommonObjectsFilter.cs delete mode 100644 Framework/CommonSerializer.cs delete mode 100644 Framework/Framework.csproj delete mode 100644 Framework/Spi.cs delete mode 100644 Framework/SpiOperations.cs delete mode 100644 Framework/version.template delete mode 100644 FrameworkInternal/Api.cs delete mode 100644 FrameworkInternal/ApiLocal.cs delete mode 100644 FrameworkInternal/ApiLocalOperations.cs delete mode 100644 FrameworkInternal/ApiRemote.cs delete mode 100644 FrameworkInternal/ApiRemoteMessages.cs delete mode 100644 FrameworkInternal/ExceptionUtil.cs delete mode 100644 FrameworkInternal/FrameworkInternal.csproj delete mode 100644 FrameworkInternal/Resources.resx delete mode 100644 FrameworkInternal/Security.cs delete mode 100644 FrameworkInternal/Serializer.cs delete mode 100644 FrameworkInternal/SerializerBinary.cs delete mode 100644 FrameworkInternal/SerializerXml.cs delete mode 100644 FrameworkInternal/Server.cs delete mode 100644 FrameworkInternal/Test.cs delete mode 100644 FrameworkInternal/version.template delete mode 100644 FrameworkTests/CollectionUtilTests.cs delete mode 100644 FrameworkTests/ConnectorAttributeUtilTests.cs delete mode 100644 FrameworkTests/ConnectorFacadeExceptionTests.cs delete mode 100755 FrameworkTests/ConnectorFacadeTests.cs delete mode 100644 FrameworkTests/ConnectorInfoManagerTests.cs delete mode 100644 FrameworkTests/ExceptionUtilTests.cs delete mode 100644 FrameworkTests/FilterTranslatorTests.cs delete mode 100644 FrameworkTests/FrameworkTests.csproj delete mode 100755 FrameworkTests/GuardedByteArrayTests.cs delete mode 100644 FrameworkTests/GuardedStringTests.cs delete mode 100644 FrameworkTests/LocaleTests.cs delete mode 100755 FrameworkTests/MockConnector.cs delete mode 100755 FrameworkTests/ObjectClassUtilTests.cs delete mode 100644 FrameworkTests/ObjectNormalizerFacadeTests.cs delete mode 100644 FrameworkTests/ObjectPoolTests.cs delete mode 100644 FrameworkTests/ObjectSerializationTests.cs delete mode 100644 FrameworkTests/Org.IdentityConnectors.TestConnector.FakeConnector/config/config.xml delete mode 100644 FrameworkTests/Org.IdentityConnectors.TestConnector.FakeConnector/config/myconfig/config.xml delete mode 100644 FrameworkTests/PropertyBagTests.cs delete mode 100644 FrameworkTests/ProxyTests.cs delete mode 100644 FrameworkTests/SafeTypeTest.cs delete mode 100644 FrameworkTests/ScriptTests.cs delete mode 100644 FrameworkTests/TestHelperTests.cs delete mode 100644 FrameworkTests/TestUtil.cs delete mode 100644 FrameworkTests/UpdateImplTests.cs delete mode 100644 FrameworkTests/app.config delete mode 100644 FrameworkTests/version.template delete mode 100644 Service/Program.cs delete mode 100644 Service/ProjectInstaller.cs delete mode 100644 Service/Service.cs delete mode 100644 Service/Service.csproj delete mode 100644 Service/app.config delete mode 100644 Service/version.template delete mode 100644 ServiceInstall/ExtBuild.proj delete mode 100644 ServiceInstall/File.bottom delete mode 100644 ServiceInstall/File.top delete mode 100644 ServiceInstall/ServiceInstall.wixproj delete mode 100644 ServiceInstall/Setup.wxs delete mode 100644 ServiceInstall/license.rtf delete mode 100644 ShellScriptExecutorFactory/ShellScriptExecutorFactory.cs delete mode 100644 ShellScriptExecutorFactory/ShellScriptExecutorFactory.csproj delete mode 100644 ShellScriptExecutorFactory/version.template delete mode 100644 TestBundleV1/AssemblyInfo.cs delete mode 100644 TestBundleV1/Messages.es-ES.resx delete mode 100644 TestBundleV1/Messages.es.resx delete mode 100644 TestBundleV1/Messages.resx delete mode 100644 TestBundleV1/TestBundleV1.csproj delete mode 100644 TestBundleV1/TestConnector.cs delete mode 100644 TestBundleV2/AssemblyInfo.cs delete mode 100644 TestBundleV2/TestBundleV2.csproj delete mode 100644 TestBundleV2/TestConnector.cs delete mode 100644 TestCommon/FrameworkInternalBridge.cs delete mode 100644 TestCommon/PropertyBag.cs delete mode 100644 TestCommon/Test.cs delete mode 100644 TestCommon/TestCommon.csproj delete mode 100644 TestCommon/TestHelpersSpi.cs delete mode 100644 TestCommon/config.xsd delete mode 100644 TestCommon/version.template delete mode 100644 server.pfx diff --git a/ActiveDirectoryConnector/ActiveDirectoryConnector.csproj b/ActiveDirectoryConnector/ActiveDirectoryConnector.csproj index 517bb05..71c1ce4 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryConnector.csproj +++ b/ActiveDirectoryConnector/ActiveDirectoryConnector.csproj @@ -1,4 +1,4 @@ - - - - {0747C440-70E4-4E63-9F9D-03B3A010C991} - Debug - AnyCPU - Library - Org.IdentityConnectors.Common.Script.Boo - Boo.ScriptExecutorFactory - BooScriptExecutorFactory - v3.5 - - - prompt - 4 - AnyCPU - bin\Debug\ - True - Full - False - True - DEBUG;TRACE - - - pdbonly - bin\Release\ - TRACE - prompt - 4 - AnyCPU - False - True - 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 - - - - 3.5 - - - - 3.5 - - - - - - - - - {F140E8DA-52B4-4159-992A-9DA10EA8EEFB} - Common - - - - - - - - diff --git a/BooScriptExecutorFactory/lib/Boo.Lang.Compiler.dll b/BooScriptExecutorFactory/lib/Boo.Lang.Compiler.dll deleted file mode 100644 index 7a4bc09ba3dce42a0b0abf3030063f29df749338..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 729088 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
GU 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

T_?v+9kPqlvw@YaP6tl3J0exTmi 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�FL@bc7u8lj-pJ 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 W7|1Y?VIadmhJg$N83z7uG4OBPtaM!f diff --git a/BooScriptExecutorFactory/lib/Boo.Lang.Interpreter.dll b/BooScriptExecutorFactory/lib/Boo.Lang.Interpreter.dll deleted file mode 100644 index 407d01147637f06a2a95f0ad3445cabc552c6683..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 86016 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 V1`afEpn(Go9BAM`1OFlo{C^)m7oGqB diff --git a/BooScriptExecutorFactory/lib/Boo.Lang.Parser.dll b/BooScriptExecutorFactory/lib/Boo.Lang.Parser.dll deleted file mode 100644 index 8bf0313d832a327a3568d7b39af0325641090f04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 421888 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

|?;D`Z! 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 T4zxJX;y{Z7Ee`yD$$|e13;By` diff --git a/BooScriptExecutorFactory/lib/Boo.Lang.Useful.dll b/BooScriptExecutorFactory/lib/Boo.Lang.Useful.dll deleted file mode 100644 index 73b494556eb679b91547b5e8e616973ae92ae8e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 81920 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 diff --git a/BooScriptExecutorFactory/lib/Boo.Lang.dll b/BooScriptExecutorFactory/lib/Boo.Lang.dll deleted file mode 100644 index 83dc5fbc52b26ef9a7916040df05d3b79b5f07ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 110592 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 - /// Description of Assertions. - /// - public static class Assertions - { - /// - /// 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) - { - String FORMAT = "Parameter '{0}' must not be null."; - if (o == null) - { - throw new ArgumentNullException(String.Format(FORMAT, param)); - } - } - - /// - /// 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) - { - String FORMAT = "Parameter '{0}' must not be blank."; - if (StringUtil.IsBlank(o)) - { - throw new ArgumentException(String.Format(FORMAT, param)); - } - } - } -} \ No newline at end of file diff --git a/Common/CollectionUtil.cs b/Common/CollectionUtil.cs deleted file mode 100644 index 731ac6b..0000000 --- a/Common/CollectionUtil.cs +++ /dev/null @@ -1,1030 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Runtime.CompilerServices; -using System.Reflection; -using System.Collections.Generic; - -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 iff the collection is a case-insensitive set - /// - /// The collection. May be null. - /// true iff 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 iff the collection is a case-insensitive map - /// - /// The map. May be null. - /// true iff 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 iff 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) - { - if (collection1 == null || collection1 == null) - { - return collection1 == null && collection1 == 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 iff c is null. - /// - /// The collection - /// c or an empty collection iff c is null. - public static ICollection NullAsEmpty(ICollection c) - { - return c ?? new HashSet(); - } - - /// - /// Returns c or an empty collection iff c is null. - /// - /// The collection - /// c or an empty collection iff c is null. - public static IDictionary NullAsEmpty(IDictionary c) - { - return c ?? new Dictionary(); - } - - /// - /// Returns c or an empty collection iff c is null. - /// - /// The collection - /// c or an empty collection iff c is null. - public static IList NullAsEmpty(IList c) - { - return c ?? new List(); - } - - /// - /// Returns c or an empty array iff c is null. - /// - /// The array - /// c or an empty collection iff 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 k1, - TValue v1) - { - IDictionary rv = new Dictionary(); - rv[k1] = v1; - 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 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((U)(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) - { - if (m1.Count != m2.Count) - { - return false; - } - foreach (KeyValuePair entry1 in m1) - { - K key1 = entry1.Key; - V val1 = entry1.Value; - if (!m2.ContainsKey(key1)) - { - return false; - } - Object val2 = m2[key1]; - if (!CollectionUtil.Equals(val1, val2)) - { - return false; - } - } - return true; - } - - public static bool ListsEqual(IList v1, - IList v2) - { - 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; - } - - /// - /// 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 += CollectionUtil.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 iff the two objects are equal. - public new static bool Equals(Object o1, Object o2) - { - 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 (!CollectionUtil.Equals(el1, el2)) - { - 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"); - - info = info.MakeGenericMethod(genericArguments); - - Object rv = info.Invoke(null, new object[] { o1, o2 }); - 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"); - - info = info.MakeGenericMethod(genericArguments); - - Object rv = info.Invoke(null, new object[] { o1, o2 }); - 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"); - - info = info.MakeGenericMethod(genericArguments); - - Object rv = info.Invoke(null, new object[] { o1, o2 }); - return (bool)rv; - } - else - { - return o1.Equals(o2); - } - } - - } - -} diff --git a/Common/Common.csproj b/Common/Common.csproj deleted file mode 100644 index bc5dee3..0000000 --- a/Common/Common.csproj +++ /dev/null @@ -1,95 +0,0 @@ - - - - {F140E8DA-52B4-4159-992A-9DA10EA8EEFB} - Debug - AnyCPU - Library - Org.IdentityConnectors.Common - Common - Open Connectors Common - v3.5 - True - False - 4 - false - - - bin\Debug\ - true - Full - False - True - DEBUG;TRACE - - - bin\Release\ - False - None - True - False - TRACE - - - False - Auto - 4194304 - AnyCPU - 4096 - - - - - - 3.5 - - - - 3.5 - - - - 3.5 - - - - - - - - - - - - - - - - - - - - - - diff --git a/Common/DateTimeUtil.cs b/Common/DateTimeUtil.cs deleted file mode 100644 index 46a7c47..0000000 --- a/Common/DateTimeUtil.cs +++ /dev/null @@ -1,47 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 - { - 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); - } - } -} diff --git a/Common/FrameworkInternalBridge.cs b/Common/FrameworkInternalBridge.cs deleted file mode 100644 index 9f3e0da..0000000 --- a/Common/FrameworkInternalBridge.cs +++ /dev/null @@ -1,58 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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/Common/IOUtil.cs b/Common/IOUtil.cs deleted file mode 100644 index 38f747d..0000000 --- a/Common/IOUtil.cs +++ /dev/null @@ -1,48 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Net; -namespace Org.IdentityConnectors.Common -{ - /// - /// 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]; - } - } -} diff --git a/Common/Locale.cs b/Common/Locale.cs deleted file mode 100644 index c0cc45a..0000000 --- a/Common/Locale.cs +++ /dev/null @@ -1,240 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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; - } - - /// - /// Special cases - /// - static Locale() - { - AddMapping(new Locale(), ""); - AddMapping(new Locale("iw"), "he"); - AddMapping(new Locale("zh"), "zh-CHS"); - AddMapping(new Locale("iw", "IL"), "he-IL"); - AddMapping(new Locale("no", "NO"), "nb-NO"); - AddMapping(new Locale("no", "NO", "NY"), "nn-NO"); - } - - private String _language; - private String _country; - private String _variant; - - public Locale() - : this("") - { - - } - - public Locale(String language) - : this(language, "") - { - } - public Locale(String language, String country) - : this(language, country, "") - { - } - public Locale(String language, String country, String variant) - { - _language = language ?? ""; - _country = country ?? ""; - _variant = variant ?? ""; - } - - public string Language - { - get - { - return _language; - } - } - - public string Country - { - get - { - return _country; - } - } - - public string Variant - { - get - { - return _variant; - } - } - - public override bool Equals(Object o) - { - Locale other = o as Locale; - if (other != null) - { - if (!Object.Equals(Language, other.Language)) - { - return false; - } - if (!Object.Equals(Country, other.Country)) - { - return false; - } - if (!Object.Equals(Variant, other.Variant)) - { - return false; - } - return true; - } - return false; - } - - public override int GetHashCode() - { - unchecked - { - return _language.GetHashCode() + _country.GetHashCode(); - } - } - - public override string ToString() - { - return Language + "_" + Country + "_" + Variant; - } - - /// - /// Creates the closest CultureInfo that maps to this locale - /// - /// The culture info - public CultureInfo ToCultureInfo() - { - CultureInfo rv = null; - String code = CollectionUtil.GetValue(Locale2CultureInfoName, this, null); - if (code != null) - { - rv = TryCultureCode(code); - } - if (rv == null) - { - if (Country.Length > 0) - { - rv = TryCultureCode(Language + "-" + Country); - } - } - if (rv == null) - { - rv = TryCultureCode(Language); - } - if (rv == null) - { - rv = CultureInfo.InvariantCulture; - } - return rv; - } - - public static Locale FindLocale(CultureInfo info) - { - String code = info.Name; - Locale rv = CollectionUtil.GetValue(CultureInfoName2Locale, code, null); - if (rv == null) - { - String[] parts = code.Split(new string[] { "-" }, - StringSplitOptions.RemoveEmptyEntries); - String language = ""; - String country = ""; - if (parts.Length > 0) - { - String l = parts[0]; - if (LooksLikeValidLanguageCode(l)) - { - language = l; - if (parts.Length > 1) - { - String c = parts[1]; - if (LooksLikeValidCountryCode(c)) - { - country = c; - } - } - } - } - rv = new Locale(language, country); - } - return rv; - } - - /// - /// Weeds out some junk - /// - /// - /// - private static bool LooksLikeValidLanguageCode(String l) - { - char[] chars = l.ToCharArray(); - return (chars.Length == 2 && - Char.IsLower(chars[0]) && - Char.IsLower(chars[1])); - } - /// - /// Weeds out some junk - /// - /// - /// - private static bool LooksLikeValidCountryCode(String l) - { - char[] chars = l.ToCharArray(); - return (chars.Length == 2 && - Char.IsUpper(chars[0]) && - Char.IsUpper(chars[1])); - } - - private static CultureInfo TryCultureCode(String code) - { - try - { - return new CultureInfo(code); - } - catch (Exception) - { - return null; - } - } - } -} diff --git a/Common/Pair.cs b/Common/Pair.cs deleted file mode 100644 index 1513441..0000000 --- a/Common/Pair.cs +++ /dev/null @@ -1,75 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 -{ - /// - /// Represents a Pair of objects - /// - public class Pair - { - public Pair() - { - } - - public Pair(T1 first, T2 second) - { - First = first; - Second = second; - } - - public T1 First { get; set; } - public T2 Second { get; set; } - - public override bool Equals(object obj) - { - Pair other = obj as Pair; - if (other != null) - { - return Object.Equals(First, other.First) && - Object.Equals(Second, other.Second); - } - return false; - } - - public override int GetHashCode() - { - int rv = 0; - if (First != null) - { - rv ^= First.GetHashCode(); - } - if (Second != null) - { - rv ^= Second.GetHashCode(); - } - return rv; - } - - public override string ToString() - { - return "( " + First + ", " + Second + " )"; - } - } -} \ No newline at end of file diff --git a/Common/Pooling.cs b/Common/Pooling.cs deleted file mode 100644 index df00961..0000000 --- a/Common/Pooling.cs +++ /dev/null @@ -1,233 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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; - -namespace Org.IdentityConnectors.Common.Pooling -{ - /// - /// Configuration for pooling objects - /// - public sealed class ObjectPoolConfiguration - { - - /// - /// Max objects (idle+active). - /// - private int _maxObjects = 10; - - /// - /// Max idle objects. - /// - private int _maxIdle = 10; - - /// - /// Max time to wait if the pool is waiting for a free object to become - /// available before failing. - /// - /// - /// Zero means don't wait - /// - private long _maxWait = 150 * 1000; - - /// - /// Minimum time to wait before evicting an idle object. - /// - /// - /// Zero means don't wait - /// - private long _minEvictableIdleTimeMillis = 120 * 1000; - - /// - /// Minimum number of idle objects. - /// - private int _minIdle = 1; - - - /// - /// Get the set number of maximum objects (idle+active) - /// - public int MaxObjects - { - get - { - return _maxObjects; - } - set - { - _maxObjects = value; - } - } - - /// - /// Get the maximum number of idle objects. - /// - public int MaxIdle - { - get - { - return _maxIdle; - } - set - { - _maxIdle = value; - } - } - - /// - /// Max time to wait if the pool is waiting for a free object to become - /// available before failing. - /// - /// - /// Zero means don't wait - /// - public long MaxWait - { - get - { - return _maxWait; - } - set - { - _maxWait = value; - } - } - - /// - /// Minimum time to wait before evicting an idle object. - /// - /// - /// Zero means don't wait - /// - public long MinEvictableIdleTimeMillis - { - get - { - return _minEvictableIdleTimeMillis; - } - set - { - _minEvictableIdleTimeMillis = value; - } - } - - /// - /// Minimum number of idle objects. - /// - public int MinIdle - { - get - { - return _minIdle; - } - set - { - _minIdle = value; - } - } - - public void Validate() - { - if (_minIdle < 0) - { - throw new InvalidOperationException("Min idle is less than zero."); - } - if (_maxObjects < 0) - { - throw new InvalidOperationException("Max active is less than zero."); - } - if (_maxIdle < 0) - { - throw new InvalidOperationException("Max idle is less than zero."); - } - if (_maxWait < 0) - { - throw new InvalidOperationException("Max wait is less than zero."); - } - if (_minEvictableIdleTimeMillis < 0) - { - throw new InvalidOperationException("Min evictable idle time millis less than zero."); - } - if (_minIdle > _maxIdle) - { - throw new InvalidOperationException("Min idle is greater than max idle."); - } - if (_maxIdle > _maxObjects) - { - throw new InvalidOperationException("Max idle is greater than max objects."); - } - } - - public override int GetHashCode() - { - unchecked - { - return (int)(MaxObjects + MaxIdle + MaxWait + MinEvictableIdleTimeMillis + MinIdle); - } - } - - public override bool Equals(Object obj) - { - if (obj is ObjectPoolConfiguration) - { - ObjectPoolConfiguration other = (ObjectPoolConfiguration)obj; - - if (MaxObjects != other.MaxObjects) - { - return false; - } - if (MaxIdle != other.MaxIdle) - { - return false; - } - if (MaxWait != other.MaxWait) - { - return false; - } - if (MinEvictableIdleTimeMillis != other.MinEvictableIdleTimeMillis) - { - return false; - } - if (MinIdle != other.MinIdle) - { - return false; - } - return true; - } - return false; - } - - public override String ToString() - { - // poor man's toString() - IDictionary bld = new Dictionary(); - bld["MaxObjects"] = MaxObjects; - bld["MaxIdle"] = MaxIdle; - bld["MaxWait"] = MaxWait; - bld["MinEvictableIdleTimeMillis"] = MinEvictableIdleTimeMillis; - bld["MinIdle"] = MinIdle; - return bld.ToString(); - } - } -} \ No newline at end of file diff --git a/Common/Proxy.cs b/Common/Proxy.cs deleted file mode 100644 index 546fd14..0000000 --- a/Common/Proxy.cs +++ /dev/null @@ -1,272 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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; -using System.Reflection.Emit; -using System.Collections.Generic; -namespace Org.IdentityConnectors.Common.Proxy -{ - /// - /// Similar to java.lang.reflect.InvocationHandler - /// - public interface InvocationHandler - { - Object - Invoke(Object proxy, MethodInfo method, Object[] args); - } - - - /// - /// Similar to java.lang.reflect.Proxy - /// - public static class Proxy - { - private static readonly MethodInfo INVOCATION_HANDLER_METHOD = - typeof(InvocationHandler).GetMethod("Invoke", - new Type[]{typeof(object), - typeof(MethodInfo), - typeof(object[])}); - private static readonly MethodInfo GET_METHOD_FROM_HANDLE_METHOD = - typeof(MethodBase).GetMethod("GetMethodFromHandle", - new Type[] { typeof(RuntimeMethodHandle) }); - - private static readonly object LOCK = new Object(); - - private static IDictionary - _implementationMap = new Dictionary(); - - private static int _count = 0; - - public static Object NewProxyInstance(Type interfaze, - InvocationHandler handler) - { - ConstructorInfo constructor = GetOrCreateConstructorInfo(interfaze); - return constructor.Invoke(new object[] { handler }); - } - - private static ConstructorInfo GetOrCreateConstructorInfo(Type type) - { - lock (LOCK) - { - ConstructorInfo rv = - CollectionUtil.GetValue(_implementationMap, type, null); - if (rv == null) - { - Type impl = GenerateImplementation(type); - rv = - impl.GetConstructor(new Type[] { typeof(InvocationHandler) }); - - _implementationMap[type] = rv; - } - return rv; - } - } - - private static String NextName() - { - int count; - lock (LOCK) - { - count = _count; - count++; - } - return "___proxy" + count; - } - - - - private static Type GenerateImplementation(Type interfaze) - { - if (!interfaze.IsInterface) - { - throw new ArgumentException("Type is not an interface: " + interfaze); - } - if (interfaze.IsGenericType) - { - throw new ArgumentException("Type is a generic type: " + interfaze); - } - - String uniqueName = NextName(); - - AssemblyName assemblyName = new AssemblyName(uniqueName); - AssemblyBuilder assemblyBuilder = - AppDomain.CurrentDomain.DefineDynamicAssembly( - assemblyName, - AssemblyBuilderAccess.RunAndSave); - // For a single-module assembly, the module name is usually - // the assembly name plus an extension. - ModuleBuilder moduleBuilder = - assemblyBuilder.DefineDynamicModule(assemblyName.Name, assemblyName.Name + ".dll"); - - TypeBuilder typeBuilder = moduleBuilder.DefineType( - uniqueName, - TypeAttributes.Public); - typeBuilder.AddInterfaceImplementation(interfaze); - - MethodInfo[] methods = interfaze.GetMethods(); - ConstructorBuilder classInitializer = - typeBuilder.DefineTypeInitializer(); - ILGenerator classInitializerCode = - classInitializer.GetILGenerator(); - //generate constructor and _handler field - FieldBuilder handlerField = - typeBuilder.DefineField("_handler", - typeof(InvocationHandler), - FieldAttributes.Private | FieldAttributes.InitOnly); - int count = 0; - foreach (MethodInfo method in methods) - { - GenerateMethod(typeBuilder, method, classInitializerCode, count, - handlerField); - count++; - } - classInitializerCode.Emit(OpCodes.Ret); - - - ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor( - MethodAttributes.Public, - CallingConventions.Standard, - new Type[] { typeof(InvocationHandler) }); - ILGenerator constructorCode = constructorBuilder.GetILGenerator(); - // For a constructor, argument zero is a reference to the new - // instance. Push it on the stack before calling the base - // class constructor. Specify the default constructor of the - // base class (System.Object) by passing an empty array of - // types (Type.EmptyTypes) to GetConstructor. - constructorCode.Emit(OpCodes.Ldarg_0); - constructorCode.Emit(OpCodes.Call, - typeof(object).GetConstructor(Type.EmptyTypes)); - constructorCode.Emit(OpCodes.Ldarg_0); - constructorCode.Emit(OpCodes.Ldarg_1); - constructorCode.Emit(OpCodes.Stfld, handlerField); - constructorCode.Emit(OpCodes.Ret); - - - Type t = typeBuilder.CreateType(); - - //assemblyBuilder.Save(assemblyName.Name+".dll"); - - return t; - } - - private static void ValidateMethod(MethodInfo info) - { - if (info.GetGenericArguments().Length != 0) - { - throw new ArgumentException( - "Method not supported since it has generic arguments: " + info); - - } - foreach (ParameterInfo parameter in info.GetParameters()) - { - if (parameter.IsOut) - { - throw new ArgumentException( - "Method not supported since it has output paramaters: " + info); - } - if (parameter.IsRetval) - { - throw new ArgumentException( - "Method not supported since it has retval paramaters: " + info); - } - } - } - - private static void GenerateMethod(TypeBuilder typeBuilder, - MethodInfo method, - ILGenerator classInitializerCode, - int methodCount, - FieldBuilder handlerField) - { - ValidateMethod(method); - - FieldBuilder methodField = - typeBuilder.DefineField("METHOD" + methodCount, - typeof(MethodInfo), - FieldAttributes.Private | FieldAttributes.InitOnly | FieldAttributes.Static); - - - - classInitializerCode.Emit(OpCodes.Ldtoken, - method); - classInitializerCode.Emit(OpCodes.Call, - GET_METHOD_FROM_HANDLE_METHOD); - classInitializerCode.Emit(OpCodes.Castclass, typeof(MethodInfo)); - classInitializerCode.Emit(OpCodes.Stsfld, methodField); - - - Type[] parameterTypes = ReflectionUtil.GetParameterTypes(method); - MethodBuilder methodBuilder = typeBuilder.DefineMethod( - method.Name, - MethodAttributes.Public | - MethodAttributes.HideBySig | - MethodAttributes.NewSlot | - MethodAttributes.Virtual | - MethodAttributes.Final, - method.CallingConvention, - method.ReturnType, - parameterTypes); - - ILGenerator methodCode = methodBuilder.GetILGenerator(); - methodCode.Emit(OpCodes.Ldarg_0); - methodCode.Emit(OpCodes.Ldfld, handlerField); - methodCode.Emit(OpCodes.Ldarg_0); - methodCode.Emit(OpCodes.Ldsfld, methodField); - methodCode.Emit(OpCodes.Ldc_I4, parameterTypes.Length); - methodCode.Emit(OpCodes.Newarr, typeof(object)); - - for (int index = 0; index < parameterTypes.Length; index++) - { - Type parameterType = parameterTypes[index]; - methodCode.Emit(OpCodes.Dup); - methodCode.Emit(OpCodes.Ldc_I4, index); - methodCode.Emit(OpCodes.Ldarg, index + 1); - if (parameterType.IsValueType) - { - methodCode.Emit(OpCodes.Box, parameterType); - } - methodCode.Emit(OpCodes.Stelem_Ref); - } - - methodCode.Emit(OpCodes.Callvirt, INVOCATION_HANDLER_METHOD); - Type returnType = method.ReturnType; - - if (typeof(void).Equals(returnType)) - { - methodCode.Emit(OpCodes.Pop); - } - else if (returnType.IsValueType) - { - methodCode.Emit(OpCodes.Unbox_Any, returnType); - } - else - { - methodCode.Emit(OpCodes.Castclass, returnType); - } - - methodCode.Emit(OpCodes.Ret); - - typeBuilder.DefineMethodOverride(methodBuilder, method); - } - } -} \ No newline at end of file diff --git a/Common/ReflectionUtil.cs b/Common/ReflectionUtil.cs deleted file mode 100644 index 7babc34..0000000 --- a/Common/ReflectionUtil.cs +++ /dev/null @@ -1,171 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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; -using System.Collections.Generic; -using System.Linq; -namespace Org.IdentityConnectors.Common -{ - /// - /// Miscellaenous reflection utilities. - /// - public static class ReflectionUtil - { - /// - /// Gets all the interfaces in the hierarchy - /// - /// - /// - public static Type[] GetAllInterfaces(Type type) - { - HashSet temp = new HashSet(); - GetAllInterfaces2(type, temp); - return temp.ToArray(); - } - - private static void GetAllInterfaces2(Type type, HashSet rv) - { - if (type != null) - { - if (type.IsInterface) - { - rv.Add(type); - } - GetAllInterfaces2(type.BaseType, rv); - foreach (Type inter in type.GetInterfaces()) - { - GetAllInterfaces2(inter, rv); - } - } - } - - /// - /// Returns the generic type definition of the given type - /// - /// - /// - public static Type[] GetTypeErasure(Type[] types) - { - Type[] rv = new Type[types.Length]; - for (int i = 0; i < types.Length; i++) - { - rv[i] = GetTypeErasure(types[i]); - } - return rv; - } - /// - /// Returns the generic type definition of the given type - /// - /// - /// - public static Type GetTypeErasure(Type type) - { - if (type.IsGenericType) - { - type = type.GetGenericTypeDefinition(); - } - return type; - } - - /// - /// Returns true iff t1 is a parent type of t2. Unlike - /// Type.isAssignableFrom, this handles generic types as - /// well. - /// - /// - /// - /// - public static bool IsParentTypeOf(Type t1, - Type t2) - { - if (t2 == null) - { - return t1 == null; - } - Type found = FindInHierarchyOf(t1, t2); - return found != null; - } - - /// - /// Finds t1 in the hierarchy of t2 or null if not found. The - /// returned value will have generic parameters applied to it. - /// - /// - /// - /// - public static Type FindInHierarchyOf(Type t1, Type t2) - { - if (t2 == null) - { - return null; - } - if (EqualsIgnoreGeneric(t1, t2)) - { - return t2; - } - Type found1 = FindInHierarchyOf(t1, t2.BaseType); - if (found1 != null) - { - return found1; - } - foreach (Type inter in t2.GetInterfaces()) - { - Type found2 = FindInHierarchyOf(t1, inter); - if (found2 != null) - { - return found2; - } - } - return null; - } - - private static bool EqualsIgnoreGeneric(Type t1, - Type t2) - { - if (t1 == null || t2 == null) - { - return t1 == null && t2 == null; - } - if (t1.IsGenericType) - { - t1 = t1.GetGenericTypeDefinition(); - } - if (t2.IsGenericType) - { - t2 = t2.GetGenericTypeDefinition(); - } - return t1.Equals(t2); - } - - public static Type[] GetParameterTypes(MethodInfo method) - { - ParameterInfo[] parameters = method.GetParameters(); - Type[] rv = new Type[parameters.Length]; - for (int i = 0; i < parameters.Length; i++) - { - rv[i] = parameters[i].ParameterType; - } - return rv; - } - } -} \ No newline at end of file diff --git a/Common/SafeType.cs b/Common/SafeType.cs deleted file mode 100644 index 07bd026..0000000 --- a/Common/SafeType.cs +++ /dev/null @@ -1,144 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 -{ - /// - /// The equivalent of java's Class<? extends...%gt; syntax. - /// Allows you to restrict a Type to a certain class hierarchy. - /// - public sealed class SafeType - where T : class - { - private readonly Type _rawType; - - /// - /// Make private so no one can create directly - /// - private SafeType(Type rawType) - { - if (!ReflectionUtil.IsParentTypeOf(typeof(T), rawType)) - { - throw new ArgumentException("Type: " + rawType + " is not a subclass of" + typeof(T)); - } - _rawType = rawType; - } - - /// - /// Returns the SafeType for a given raw type. - /// NOTE: If possible use Get() instead since it is statically - /// checked at compile time. - /// - /// - /// - public static SafeType ForRawType(Type type) - { - return new SafeType(type); - } - - /// - /// Gets an instance of the safe type in a type-safe fashion. - /// - /// The instance of the safe type - public static SafeType Get() - where U : T - { - return new SafeType(typeof(U)); - } - - /// - /// Gets an instance of the safe type in a type-safe fashion from an object. - /// - /// The instance of the safe type - public static SafeType Get(T obj) - { - return new SafeType(obj.GetType()); - } - - /// - /// Returns the generic type definition corresponding to this type. - /// Will return the same type if this is already a generic type. - /// - /// - public SafeType GetTypeErasure() - { - return SafeType.ForRawType(ReflectionUtil.GetTypeErasure(RawType)); - } - - /// - /// Returns the underlying C# type - /// - public Type RawType - { - get - { - return _rawType; - } - } - - /// - /// Creates a new instance of the given type - /// - /// The new instance - public T CreateInstance() - { - return (T)Activator.CreateInstance(RawType); - } - - /// - /// Returns true iff these represent the same underlying type - /// and the SafeType has the same parent type. - /// - /// The other - /// true iff these represent the same underylying type - /// and the TypeGroup has the same parent type - public override bool Equals(object o) - { - if (o is SafeType) - { - SafeType other = (SafeType)o; - return RawType.Equals(other.RawType); - } - return false; - } - /// - /// Returns a hash of the type - /// - /// a hash of the type - public override int GetHashCode() - { - return RawType.GetHashCode(); - } - /// - /// Returns a string representation of the member type - /// - /// a string representation of the member type - public override string ToString() - { - return RawType.ToString(); - } - } -} \ No newline at end of file diff --git a/Common/Script.cs b/Common/Script.cs deleted file mode 100644 index ea41773..0000000 --- a/Common/Script.cs +++ /dev/null @@ -1,182 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.IO; -using System.Reflection; -using System.Collections.Generic; -using System.Diagnostics; - -namespace Org.IdentityConnectors.Common.Script -{ - public interface ScriptExecutor - { - /// - /// Executes the script with the given arguments. - /// - /// key/value set of variables to - /// pass to the script. - /// - object Execute(IDictionary arguments); - } - public abstract class ScriptExecutorFactory - { - - private static readonly object LOCK = new object(); - - /// - /// Loaded w/ all supported languages. - /// - private static IDictionary _supportedLanguages = null; - - /// - /// Load all script executor factory assemblies in the same directory - /// the 'Common' assembly. - /// - private static IDictionary LoadSupportedLanguages() - { - // attempt to process all assemblies.. - IDictionary ret = new Dictionary(); - Assembly assembly = Assembly.GetExecutingAssembly(); - FileInfo thisAssemblyFile = new FileInfo(assembly.Location); - DirectoryInfo directory = thisAssemblyFile.Directory; - // get all *ScriptExecutorFactory assmebly from the current directory - FileInfo[] files = directory.GetFiles("*.ScriptExecutorFactory.dll"); - Type t = typeof(ScriptExecutorFactoryClassAttribute); - foreach (FileInfo file in files) - { - try - { - Assembly lib = Assembly.LoadFrom(file.ToString()); - foreach (Type type in lib.GetTypes()) - { - Object[] attributes = type.GetCustomAttributes(t, false); - if (attributes.Length > 0) - { - ScriptExecutorFactoryClassAttribute attribute = - (ScriptExecutorFactoryClassAttribute)attributes[0]; - // attempt to test assembly.. - Activator.CreateInstance(type); - // if we made it this far its okay - ret[attribute.Language.ToUpper()] = type; - } - } - } - catch (Exception e) - { - TraceUtil.TraceException("Unable to load assembly: " + - assembly.FullName + ". This is a fatal exception: ", e); - throw; - } - } - return ret; - } - - private static IDictionary GetSupportedLanguages() - { - lock (LOCK) - { - if (_supportedLanguages == null) - { - _supportedLanguages = LoadSupportedLanguages(); - } - return _supportedLanguages; - } - } - - /// - /// Returns the set of supported languages. - /// - /// The set of supported languages. - public static ICollection SupportedLanguages - { - get - { - IDictionary map = - GetSupportedLanguages(); - return CollectionUtil.AsReadOnlySet(map.Keys); - } - } - - /// - /// Creates a ScriptExecutorFactory for the given language - /// - /// The name of the language - /// The script executor factory - /// If the given language is not - /// supported. - public static ScriptExecutorFactory NewInstance(String language) - { - if (language == null) - { - throw new ArgumentException("Language must be specified"); - } - Type type = CollectionUtil.GetValue(GetSupportedLanguages(), language.ToUpper(), null); - if (type == null) - { - throw new ArgumentException("Language not supported: " + language); - } - return (ScriptExecutorFactory)Activator.CreateInstance(type); - } - - - /// - /// Creates a script executor for the given script. - /// - /// The classloader that contains the java classes - /// that the script should have access to. - /// The script text. - /// A hint to tell the script executor whether or - /// not to compile the given script. This need not be implemented - /// by all script executors. If true, the caller is saying that - /// they intend to call the script multiple times with different - /// arguments, so compile if possible. - /// A script executor. - public abstract ScriptExecutor NewScriptExecutor( - Assembly[] referencedAssemblies, - String script, - bool compile); - } - - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] - public class ScriptExecutorFactoryClassAttribute : System.Attribute - { - private readonly string _lang; - - /// - /// Determine the language supported by the factory. - /// - /// - public ScriptExecutorFactoryClassAttribute(string lang) - { - _lang = lang; - } - - public string Language - { - get - { - return _lang; - } - } - } -} \ No newline at end of file diff --git a/Common/Security.cs b/Common/Security.cs deleted file mode 100644 index c497e87..0000000 --- a/Common/Security.cs +++ /dev/null @@ -1,876 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Security; -using System.Security.Cryptography; -using System.Runtime.InteropServices; -using System.Text; -namespace Org.IdentityConnectors.Common.Security -{ - #region UnmanagedArray - /// - /// Places an array facade on an unmanaged memory data structure that - /// holds senstive data. (In C# placing senstive data in managed - /// memory is considered unsecure since the memory model allows - /// data to be copied around). - /// - public interface UnmanagedArray : IDisposable - { - int Length { get; } - T this[int index] { get; set; } - } - #endregion - - /// - /// Secure byte array implementation that solves the problems associated with - /// keeping confidential data as byte[]. - /// - /// - /// That is, anything - /// represented as a byte[] is kept in memory in clear - /// text and stays in memory at least until it is garbage collected. - /// - /// The GuardedByteArray class alleviates this problem by storing the bytes in - /// memory in an encrypted form. The encryption key will be a randomly-generated - /// key. - /// - /// - /// In their serialized form, GuardedByteArray will be encrypted using a known - /// default key. This is to provide a minimum level of protection regardless - /// of the transport. For communications with the Remote Connector Framework - /// it is recommended that deployments enable SSL for true encryption. - /// - /// - /// Applications may also wish to persist GuardedByteArrays. In the case of - /// Identity Manager, it should convert GuardedByteArrays to EncryptedData so - /// that they can be stored and managed using the Manage Encryption features - /// of Identity Manager. Other applications may wish to serialize APIConfiguration - /// as a whole. These applications are responsible for encrypting the APIConfiguration - /// blob for an additional layer of security (beyond the basic default key encryption - /// provided by GuardedByteArray). - /// - /// - public sealed class GuardedByteArray : IDisposable - { - /// - /// This method will be called with the clear text of the byte array. - /// - /// - /// After the call the clearBytes array will be automatically zeroed - /// out, thus keeping the window of potential exposure to a bare-minimum. - /// - /// - public delegate void Accessor(UnmanagedArray clearBytes); - - - private SecureString _target; - private String _base64SHA1Hash; - - /// - /// Creates an empty secure byte array. - /// - public GuardedByteArray() - { - _target = new SecureString(); - ComputeHash(); - } - - public GuardedByteArray(UnmanagedArray clearBytes) - { - _target = new SecureString(); - AppendBytes(clearBytes); - } - - private GuardedByteArray(SecureString str) - { - _target = str.Copy(); - ComputeHash(); - } - - - /// - /// Provides access to the clear-text value of the bytes in a controlled fashion. - /// - /// - /// The clear-text bytes will only be available for the duration of the call - /// and automatically zeroed out following the call. - /// - /// NOTE: Callers are encouraged to use - /// where possible if the intended use is merely to verify the contents of - /// the string match an expected hash value. - /// - /// - /// Accessor callback. - /// If the byte array has been disposed - public void Access(Accessor accessor) - { - using (SecureStringToByteArrayAdapter adapter = new SecureStringToByteArrayAdapter(_target)) - { - accessor(adapter); - } - } - - /// - /// Appends a single clear-text byte to the secure byte array. - /// - /// - /// The in-memory data will be decrypted, the character will be - /// appended, and then it will be re-encrypted. - /// - /// The byte to append. - /// If the byte array is read-only - /// If the byte array has been disposed - public void AppendByte(byte b) - { - _target.AppendChar((char)b); - ComputeHash(); - } - - private void AppendBytes(UnmanagedArray clearBytes) - { - for (int i = 0; i < clearBytes.Length; i++) - { - _target.AppendChar((char)clearBytes[i]); - } - ComputeHash(); - } - - /// - /// Clears the in-memory representation of the byte array. - /// - public void Dispose() - { - _target.Dispose(); - } - - /// - /// Returns true iff this byte array has been marked read-only - /// - /// true iff this byte array has been marked read-only - /// If the byte array has been disposed - public bool IsReadOnly() - { - return _target.IsReadOnly(); - } - - /// - /// Mark this byte array as read-only. - /// - /// If the byte array has been disposed - public void MakeReadOnly() - { - _target.MakeReadOnly(); - } - - /// - /// Create a copy of the byte array. - /// - /// - /// If this instance is read-only, - /// the copy will not be read-only. - /// - /// A copy of the byte array. - /// If the byte array has been disposed - public GuardedByteArray Copy() - { - SecureString t2 = _target.Copy(); - GuardedByteArray rv = new GuardedByteArray(t2); - return rv; - } - - /// - /// Verifies that this base-64 encoded SHA1 hash of this byte array - /// matches the given value. - /// - /// The hash to verify against. - /// True if the hash matches the given parameter. - /// If the byte array has been disposed - public bool VerifyBase64SHA1Hash(String hash) - { - CheckNotDisposed(); - return _base64SHA1Hash.Equals(hash); - } - - public string GetBase64SHA1Hash() - { - CheckNotDisposed(); - return _base64SHA1Hash; - } - - - - private void CheckNotDisposed() - { - //this throws if disposed - _target.IsReadOnly(); - } - - - public override bool Equals(Object o) - { - if (o is GuardedByteArray) - { - GuardedByteArray other = (GuardedByteArray)o; - //not the true contract of equals. however, - //due to the high mathematical improbability of - //two unequal strings having the same secure hash, - //this approach feels good. the alternative, - //decrypting for comparison, is simply too - //performance intensive to be used for equals - return _base64SHA1Hash.Equals(other._base64SHA1Hash); - } - return false; - } - - public override int GetHashCode() - { - return _base64SHA1Hash.GetHashCode(); - } - - private void ComputeHash() - { - Access(array => - { - _base64SHA1Hash = SecurityUtil.ComputeBase64SHA1Hash(array); - }); - } - - } - - /// - /// Secure string implementation that solves the problems associated with - /// keeping passwords as java.lang.String. - /// - /// - /// That is, anything - /// represented as a String is kept in memory as a clear - /// text password and stays in memory at least until it is garbage collected. - /// - /// The GuardedString class alleviates this problem by storing the characters in - /// memory in an encrypted form. The encryption key will be a randomly-generated - /// key. - /// - /// - /// In their serialized form, GuardedString will be encrypted using a known - /// default key. This is to provide a minimum level of protection regardless - /// of the transport. For communications with the Remote Connector Framework - /// it is recommended that deployments enable SSL for true encryption. - /// - /// - /// Applications may also wish to persist GuardedStrings. In the case of - /// Identity Manager, it should convert GuardedStrings to EncryptedData so - /// that they can be stored and managed using the Manage Encryption features - /// of Identity Manager. Other applications may wish to serialize APIConfiguration - /// as a whole. These applications are responsible for encrypting the APIConfiguration - /// blob for an additional layer of security (beyond the basic default key encryption - /// provided by GuardedString). - /// - /// - public sealed class GuardedString : IDisposable - { - /// - /// This method will be called with the clear text of the string. - /// - /// - /// After the call the clearChars array will be automatically zeroed - /// out, thus keeping the window of potential exposure to a bare-minimum. - /// - /// - public delegate void Accessor(UnmanagedArray clearChars); - - - private SecureString _target; - private String _base64SHA1Hash; - - /// - /// Creates an empty secure string - /// - public GuardedString() - { - _target = new SecureString(); - ComputeHash(); - } - - public GuardedString(SecureString str) - { - _target = str.Copy(); - ComputeHash(); - } - - - /// - /// Provides access to the clear-text value of the string in a controlled fashion. - /// - /// - /// The clear-text characters will only be available for the duration of the call - /// and automatically zeroed out following the call. - /// - /// NOTE: Callers are encouraged to use - /// where possible if the intended use is merely to verify the contents of - /// the string match an expected hash value. - /// - /// - /// Accessor callback. - /// If the string has been disposed - public void Access(Accessor accessor) - { - using (SecureStringAdapter adapter = new SecureStringAdapter(_target)) - { - accessor(adapter); - } - } - - /// - /// Appends a single clear-text character to the secure string. - /// - /// - /// The in-memory data will be decrypted, the character will be - /// appended, and then it will be re-encrypted. - /// - /// The character to append. - /// If the string is read-only - /// If the string has been disposed - public void AppendChar(char c) - { - _target.AppendChar(c); - ComputeHash(); - } - - /// - /// Clears the in-memory representation of the string. - /// - public void Dispose() - { - _target.Dispose(); - } - - /// - /// Returns true iff this string has been marked read-only - /// - /// true iff this string has been marked read-only - /// If the string has been disposed - public bool IsReadOnly() - { - return _target.IsReadOnly(); - } - - /// - /// Mark this string as read-only. - /// - /// If the string has been disposed - public void MakeReadOnly() - { - _target.MakeReadOnly(); - } - - /// - /// Create a copy of the string. - /// - /// - /// If this instance is read-only, - /// the copy will not be read-only. - /// - /// A copy of the string. - /// If the string has been disposed - public GuardedString Copy() - { - SecureString t2 = _target.Copy(); - GuardedString rv = new GuardedString(t2); - return rv; - } - - /// - /// Verifies that this base-64 encoded SHA1 hash of this string - /// matches the given value. - /// - /// The hash to verify against. - /// True if the hash matches the given parameter. - /// If the string has been disposed - public bool VerifyBase64SHA1Hash(String hash) - { - CheckNotDisposed(); - return _base64SHA1Hash.Equals(hash); - } - - public string GetBase64SHA1Hash() - { - CheckNotDisposed(); - return _base64SHA1Hash; - } - - - - private void CheckNotDisposed() - { - //this throws if disposed - _target.IsReadOnly(); - } - - - public override bool Equals(Object o) - { - if (o is GuardedString) - { - GuardedString other = (GuardedString)o; - //not the true contract of equals. however, - //due to the high mathematical improbability of - //two unequal strings having the same secure hash, - //this approach feels good. the alternative, - //decrypting for comparison, is simply too - //performance intensive to be used for equals - return _base64SHA1Hash.Equals(other._base64SHA1Hash); - } - return false; - } - - public override int GetHashCode() - { - return _base64SHA1Hash.GetHashCode(); - } - - public SecureString ToSecureString() - { - return _target.Copy(); - } - - private void ComputeHash() - { - Access(array => - { - _base64SHA1Hash = SecurityUtil.ComputeBase64SHA1Hash(array); - }); - } - - } - - - #region AbstractUnmanagedArray - public abstract class AbstractUnmanagedArray : UnmanagedArray - { - private readonly int _length; - private bool _disposed; - public AbstractUnmanagedArray(int length) - { - if (length < 0) - { - throw new ArgumentException("Invalid length: " + length); - } - _length = length; - } - public int Length - { - get - { - if (_disposed) - { - throw new ObjectDisposedException("UnmanagedArray"); - } - return _length; - } - } - public T this[int index] - { - get - { - if (_disposed) - { - throw new ObjectDisposedException("UnmanagedArray"); - } - if (index < 0 || index >= Length) - { - throw new IndexOutOfRangeException(); - } - return GetValue(index); - } - set - { - if (_disposed) - { - throw new ObjectDisposedException("SecureStringAdapter"); - } - if (index < 0 || index >= Length) - { - throw new IndexOutOfRangeException(); - } - SetValue(index, value); - } - } - public void Dispose() - { - if (!_disposed) - { - for (int i = 0; i < Length; i++) - { - this[i] = default(T); - } - _disposed = true; - FreeMemory(); - } - } - - abstract protected T GetValue(int index); - abstract protected void SetValue(int index, T val); - abstract protected void FreeMemory(); - } - #endregion - - #region SecureStringAdapter - internal class SecureStringAdapter : AbstractUnmanagedArray - { - private IntPtr _bstrPtr; - public SecureStringAdapter(SecureString secureString) - : base(secureString.Length) - { - Assertions.NullCheck(secureString, "secureString"); - _bstrPtr = Marshal.SecureStringToBSTR(secureString); - } - protected override char GetValue(int index) - { - unsafe - { - char* charPtr = (char*)_bstrPtr; - return *(charPtr + index); - } - } - protected override void SetValue(int index, char c) - { - unsafe - { - char* charPtr = (char*)_bstrPtr; - *(charPtr + index) = c; - } - } - protected override void FreeMemory() - { - Marshal.ZeroFreeBSTR(_bstrPtr); - } - } - #endregion - - #region SecureStringToByteArrayAdapter - internal class SecureStringToByteArrayAdapter : AbstractUnmanagedArray - { - private IntPtr _bstrPtr; - public SecureStringToByteArrayAdapter(SecureString secureString) - : base(secureString.Length) - { - Assertions.NullCheck(secureString, "secureString"); - _bstrPtr = Marshal.SecureStringToBSTR(secureString); - } - protected override byte GetValue(int index) - { - unsafe - { - char* charPtr = (char*)_bstrPtr; - return (byte)*(charPtr + index); - } - } - protected override void SetValue(int index, byte b) - { - unsafe - { - char* charPtr = (char*)_bstrPtr; - *(charPtr + index) = (char)b; - } - } - protected override void FreeMemory() - { - Marshal.ZeroFreeBSTR(_bstrPtr); - } - } - #endregion - - #region UnmanagedCharArray - public class UnmanagedCharArray : AbstractUnmanagedArray - { - private IntPtr _ptr; - public UnmanagedCharArray(int length) - : base(length) - { - unsafe - { - _ptr = Marshal.AllocHGlobal(length * sizeof(char)); - } - } - protected override char GetValue(int index) - { - unsafe - { - char* charPtr = (char*)_ptr; - return *(charPtr + index); - } - } - protected override void SetValue(int index, char c) - { - unsafe - { - char* charPtr = (char*)_ptr; - *(charPtr + index) = c; - } - } - protected override void FreeMemory() - { - Marshal.FreeHGlobal(_ptr); - } - } - #endregion - - #region UnmanagedByteArray - public class UnmanagedByteArray : AbstractUnmanagedArray - { - private IntPtr _ptr; - public UnmanagedByteArray(int length) - : base(length) - { - unsafe - { - _ptr = Marshal.AllocHGlobal(length * sizeof(byte)); - } - } - protected override byte GetValue(int index) - { - unsafe - { - byte* charPtr = (byte*)_ptr; - return *(charPtr + index); - } - } - protected override void SetValue(int index, byte c) - { - unsafe - { - byte* charPtr = (byte*)_ptr; - *(charPtr + index) = c; - } - } - protected override void FreeMemory() - { - Marshal.FreeHGlobal(_ptr); - } - } - #endregion - - #region SecurityUtil - /// - /// Description of SecurityUtil. - /// - public static class SecurityUtil - { - - /// - /// Converts chars to bytes without using any external functions - /// that might allocate additional buffers for the potentially - /// sensitive data. - /// - /// - /// This guarantees the caller that they only - /// need to cleanup the input and result. - /// - /// The chars - /// The bytes - public static UnmanagedArray CharsToBytes(UnmanagedArray chars) - { - UnmanagedByteArray bytes = new UnmanagedByteArray(chars.Length * 2); - - for (int i = 0; i < chars.Length; i++) - { - char v = chars[i]; - bytes[i * 2] = (byte)(0xff & (v >> 8)); - bytes[i * 2 + 1] = (byte)(0xff & (v)); - } - return bytes; - } - - /// - /// Converts bytes to chars without using any external functions - /// that might allocate additional buffers for the potentially - /// sensitive data. - /// - /// - /// This guarantees the caller that they only - /// need to cleanup the input and result. - /// - /// The chars - /// The bytes - public static UnmanagedArray BytesToChars(UnmanagedArray bytes) - { - UnmanagedCharArray chars = new UnmanagedCharArray(bytes.Length / 2); - for (int i = 0; i < chars.Length; i++) - { - char v = (char)((bytes[i * 2] << 8) | bytes[i * 2 + 1]); - chars[i] = v; - } - return chars; - } - - - public unsafe static string ComputeBase64SHA1Hash(UnmanagedArray input) - { - using (UnmanagedArray bytes = SecurityUtil.CharsToBytes(input)) - { - return ComputeBase64SHA1Hash(bytes); - } - } - - public unsafe static string ComputeBase64SHA1Hash(UnmanagedArray input) - { - byte[] managedBytes = new byte[input.Length]; - fixed (byte* dummy = managedBytes) - { //pin it - try - { - //populate it in pinned block - SecurityUtil.UnmanagedBytesToManagedBytes(input, managedBytes); - SHA1 hasher = SHA1.Create(); - byte[] data = hasher.ComputeHash(managedBytes); - return Convert.ToBase64String(data); - } - finally - { - //clear it before we leave pinned block - SecurityUtil.Clear(managedBytes); - } - } - } - - /// - /// Copies an unmanaged byte array into a managed byte array. - /// - /// - /// NOTE: it is imperative for security reasons that this only - /// be done in a context where the byte array in question is pinned. - /// moreover, the byte array must be cleared prior to leaving the - /// pinned block - /// - public static void UnmanagedBytesToManagedBytes(UnmanagedArray array, - byte[] bytes) - { - for (int i = 0; i < array.Length; i++) - { - bytes[i] = array[i]; - } - } - - /// - /// Clears an array of potentially sensitive bytes - /// - /// The bytes. May be null. - /// NOTE: because this is C#, this alone is not enough. The - /// array must be pinned during the interval it is in-use or - /// it could be copied out from under you. - public static void Clear(byte[] bytes) - { - if (bytes != null) - { - for (int i = 0; i < bytes.Length; i++) - { - bytes[i] = 0; - } - } - } - - /// - /// Clears an array of potentially sensitive chars - /// - /// The characters. May be null. - /// NOTE: because this is C#, this alone is not enough. The - /// array must be pinned during the interval it is in-use or - /// it could be copied out from under you. - public static void Clear(char[] chars) - { - if (chars != null) - { - for (int i = 0; i < chars.Length; i++) - { - chars[i] = (char)0; - } - } - } - - public static bool VerifyBase64SHA1Hash(UnmanagedArray input, string hash) - { - string inputHash = ComputeBase64SHA1Hash(input); - return inputHash.Equals(hash); - } - } - #endregion - - #region Encryptor - /// - /// Responsible for encrypting/decrypting bytes. - /// - /// - /// Implementations - /// are intended to be thread-safe. - /// - public interface Encryptor - { - /// - /// Decrypts the given byte array - /// - /// The encrypted bytes - /// The decrypted bytes - UnmanagedArray Decrypt(byte[] bytes); - - /// - /// Encrypts the given byte array - /// - /// The clear bytes - /// The ecnrypted bytes - byte[] Encrypt(UnmanagedArray bytes); - } - #endregion - - #region EncryptorFactory - public abstract class EncryptorFactory - { - private static readonly object LOCK = new object(); - - // At some point we might make this pluggable, but for now, hard-code - private const String IMPL_NAME = "Org.IdentityConnectors.Common.Security.Impl.EncryptorFactoryImpl"; - - private static EncryptorFactory _instance; - - /// - /// Get the singleton instance of the . - /// - public static EncryptorFactory GetInstance() - { - lock (LOCK) - { - if (_instance == null) - { - Type type = FrameworkInternalBridge.LoadType(IMPL_NAME); - _instance = (EncryptorFactory)Activator.CreateInstance(type); - } - return _instance; - } - } - - /// - /// Default encryptor that encrypts/descrypts using a default key - /// - public abstract Encryptor GetDefaultEncryptor(); - } - #endregion -} \ No newline at end of file diff --git a/Common/StringUtil.cs b/Common/StringUtil.cs deleted file mode 100644 index daebf33..0000000 --- a/Common/StringUtil.cs +++ /dev/null @@ -1,97 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 Org.IdentityConnectors.Common.Security; -namespace Org.IdentityConnectors.Common -{ - public static class StringUtil - { - /// - /// Determines if a string is empty. - /// - /// - /// Empty is defined as null or empty - /// string. - ///
-        /// StringUtil.isEmpty(null)               = true
-        /// StringUtil.isEmpty("")       = true
-        /// StringUtil.isEmpty(" ")      = false
-        /// StringUtil.isEmpty("bob")    = false
-        /// StringUtil.isEmpty(" bob ")  = false
-        /// 
- ///
- /// string to evaluate as empty. - /// true if the string is empty else false. - public static bool IsEmpty(String val) - { - return (val == null) ? true : val.Length == 0; - } - - /// - ///
-        /// StringUtil.isBlank(null)                = true
-        /// StringUtil.isBlank("")        = true
-        /// StringUtil.isBlank(" ")       = true
-        /// StringUtil.isBlank("bob")     = false
-        /// StringUtil.isBlank("  bob  ") = false
-        /// 
- ///
- public static bool IsBlank(String val) - { - return (val == null) ? true : IsEmpty(val.Trim()); - } - - /// - /// Constructs a secure string from a char []. The char[] will - /// be cleared out when finished. - /// - /// The characters to use. Will be cleared - /// out. - /// A secure string representation - public static GuardedString NewGuardedString(char[] val) - { - GuardedString rv = new GuardedString(); - for (int i = 0; i < val.Length; i++) - { - rv.AppendChar(val[i]); - val[i] = (char)0; - } - return rv; - } - - - public static bool IsTrue(string val) - { - if (!IsBlank(val)) - { - // clean up the value.. - val = val.Trim().ToLower(); - if (val.Equals("1") || val.Equals("on") || val.Equals("true")) - { - return true; - } - } - return false; - } - } -} \ No newline at end of file diff --git a/Common/TraceUtil.cs b/Common/TraceUtil.cs deleted file mode 100644 index bf5fbc4..0000000 --- a/Common/TraceUtil.cs +++ /dev/null @@ -1,52 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Diagnostics; -using System.Text; -namespace Org.IdentityConnectors.Common -{ - /// - /// Description of TraceUtil. - /// - public static class TraceUtil - { - /// - /// Traces an exception with its stack trace - /// - /// An optional error message to display in addition to the exception - /// The exception - public static void TraceException(String msg, Exception e) - { - StringBuilder builder = new StringBuilder(); - if (msg != null) - { - builder.AppendLine(msg); - } - if (e != null) - { - builder.AppendLine(e.ToString()); - } - Trace.TraceError(builder.ToString()); - } - } -} \ No newline at end of file diff --git a/Common/XmlUtil.cs b/Common/XmlUtil.cs deleted file mode 100644 index 6f4894d..0000000 --- a/Common/XmlUtil.cs +++ /dev/null @@ -1,225 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Xml; -using System.Text; -namespace Org.IdentityConnectors.Common -{ - /// - /// Description of XmlUtil. - /// - public static class XmlUtil - { - ///////////////////////////////////////////////////////////// - // - // DOM Navigation utilities - // - //////////////////////////////////////////////////////////// - - /// - /// Return the value of an attribute on an element. - /// - /// - ///

The DOM getAttribute - /// method returns an empty string if the attribute doesn't exist. Here, we - /// detect this and return null. - /// - public static String GetAttribute(XmlElement e, String name) - { - String value = e.GetAttribute(name); - if (value != null && value.Length == 0) - value = null; - return value; - } - - ///

- /// Find an immediate child of the given name - /// - public static XmlElement FindImmediateChildElement(XmlNode node, String name) - { - - XmlElement found = null; - - if (node != null) - { - - for (XmlNode child = node.FirstChild; child != null - && found == null; child = child.NextSibling) - { - - if (child.NodeType == XmlNodeType.Element) - { - XmlElement tmp = (XmlElement)child; - if (tmp.LocalName.Equals(name)) - { - return tmp; - } - } - } - } - - return found; - } - - /// - /// Returns the First child element or null if none found - /// - /// The node. May be null. - /// the First child element or null if none found - public static XmlElement GetFirstChildElement(XmlNode node) - { - if (node == null) - { - return null; - } - XmlNode child = node.FirstChild; - if (child != null && child.NodeType == XmlNodeType.Element) - { - return (XmlElement)child; - } - else - { - return GetNextElement(child); - } - } - - /// - /// Get the next right sibling that is an element. - /// - public static XmlElement GetNextElement(XmlNode node) - { - - XmlElement found = null; - - if (node != null) - { - - for (XmlNode next = node.NextSibling; next != null - && found == null; next = next.NextSibling) - { - - if (next.NodeType == XmlNodeType.Element) - found = (XmlElement)next; - } - } - - return found; - } - - /// - /// Locate the first text node at any level below the given node. - /// - /// - /// If the - /// ignoreEmpty flag is true, we will ignore text nodes that contain only - /// whitespace characteres.

Note that if you're trying to extract - /// element content, you probably don't want this since parser's can break up - /// pcdata into multiple adjacent text nodes. See getContent() for a more - /// useful method. - /// - private static XmlText FindText(XmlNode node, bool ignoreEmpty) - { - - XmlText found = null; - - if (node != null) - { - - if (node.NodeType == XmlNodeType.Text - || node.NodeType == XmlNodeType.CDATA) - { - - XmlText t = (XmlText)node; - if (!ignoreEmpty) - found = t; - else - { - String s = t.Data.Trim(); - if (s.Length > 0) - found = t; - } - } - - if (found == null) - { - - for (XmlNode child = node.FirstChild; child != null - && found == null; child = child.NextSibling) - { - - found = FindText(child, ignoreEmpty); - } - } - } - - return found; - } - - - ///

- /// Return the content of the given element. - /// - /// - ///

We will descend to an - /// arbitrary depth looking for the first text node.

Note that - /// the parser may break what was originally a single string of pcdata into - /// multiple adjacent text nodes. Xerces appears to do this when it - /// encounters a '$' in the text, not sure if there is specified behavior, or - /// if its parser specific.

Here, we will congeal adjacent text nodes. - ///

We will NOT ignore text nodes that have only whitespace. - /// - public static String GetContent(XmlElement e) - { - - String content = null; - - if (e != null) - { - - // find the first inner text node, - XmlText t = FindText(e, false); - if (t != null) - { - // we have at least some text - StringBuilder b = new StringBuilder(); - while (t != null) - { - b.Append(t.Data); - XmlNode n = t.NextSibling; - - t = null; - if (n != null - && ((n.NodeType == XmlNodeType.Text) || - (n.NodeType == XmlNodeType.CDATA))) - { - t = (XmlText)n; - } - } - content = b.ToString(); - } - } - - return content; - } - } -} \ No newline at end of file diff --git a/Common/version.template b/Common/version.template deleted file mode 100644 index db70057..0000000 --- a/Common/version.template +++ /dev/null @@ -1 +0,0 @@ -1.2.0.0 diff --git a/Console/Console.csproj b/Console/Console.csproj deleted file mode 100644 index 91a41b0..0000000 --- a/Console/Console.csproj +++ /dev/null @@ -1,91 +0,0 @@ - - - - {D09E6A1F-55F6-4661-8E5A-C485E4B08BB3} - Debug - AnyCPU - WinExe - Console - Console - Console - v3.5 - - - prompt - AnyCPU - ./bin/Debug/ - True - Full - False - True - DEBUG;TRACE - WinExe - Console - False - 4 - - - pdbonly - AnyCPU - ./bin/Release/ - False - True - False - TRACE - WinExe - Console - False - 4 - - - - - ..\..\..\..\..\..\..\Program Files\SharpDevelop\3.0\AddIns\AddIns\BackendBindings\BooBinding\Boo.Lang.dll - - - - 3.5 - - - - - - - - - - Form - - - MainForm.cs - - - - - - {8B24461B-456A-4032-89A1-CD418F7B5B62} - Framework - - - diff --git a/Console/MainForm.Designer.cs b/Console/MainForm.Designer.cs deleted file mode 100644 index 1782f06..0000000 --- a/Console/MainForm.Designer.cs +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Created by SharpDevelop. - * User: Administrator - * Date: 3/18/2008 - * Time: 4:30 PM - * - * To change this template use Tools | Options | Coding | Edit Standard Headers. - */ -namespace Console -{ - partial class MainForm - { - ///

- /// Designer variable used to keep track of non-visual components. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Disposes resources used by the form. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing) { - if (components != null) { - components.Dispose(); - } - } - base.Dispose(disposing); - } - - /// - /// This method is required for Windows Forms designer support. - /// Do not change the method contents inside the source code editor. The Forms designer might - /// not be able to load this method if it was changed manually. - /// - private void InitializeComponent() - { - // - // MainForm - // - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.Text = "Console"; - this.Name = "MainForm"; - } - } -} diff --git a/Console/MainForm.cs b/Console/MainForm.cs deleted file mode 100644 index ac181ad..0000000 --- a/Console/MainForm.cs +++ /dev/null @@ -1,47 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Drawing; -using System.Windows.Forms; - -namespace Console -{ - /// - /// Description of MainForm. - /// - public partial class MainForm : Form - { - public MainForm() - { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - - // - // TODO: Add constructor code after the InitializeComponent() call. - // - } - } -} diff --git a/Console/Program.cs b/Console/Program.cs deleted file mode 100644 index 6bf701a..0000000 --- a/Console/Program.cs +++ /dev/null @@ -1,45 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Windows.Forms; - -namespace Console -{ - /// - /// Class with program entry point. - /// - internal sealed class Program - { - /// - /// Program entry point. - /// - [STAThread] - private static void Main(string[] args) - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - Application.Run(new MainForm()); - } - - } -} diff --git a/Console/version.template b/Console/version.template deleted file mode 100644 index bd2666a..0000000 --- a/Console/version.template +++ /dev/null @@ -1 +0,0 @@ -1.0.0.0 \ No newline at end of file diff --git a/DotNetConnectors.sln b/DotNetConnectors.sln index b362783..ceddedc 100644 --- a/DotNetConnectors.sln +++ b/DotNetConnectors.sln @@ -1,84 +1,15 @@ - Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Service", "Service\Service.csproj", "{A9D6374A-D51F-4FA3-8C02-5B1D23FAA82E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Framework", "Framework\Framework.csproj", "{8B24461B-456A-4032-89A1-CD418F7B5B62}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "Common\Common.csproj", "{F140E8DA-52B4-4159-992A-9DA10EA8EEFB}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrameworkTests", "FrameworkTests\FrameworkTests.csproj", "{32804F5A-812C-4FA6-835C-BDAE5B24D355}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestBundleV1", "TestBundleV1\TestBundleV1.csproj", "{0BC2A013-56FE-46DD-90FC-2D2D57748FB6}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestBundleV2", "TestBundleV2\TestBundleV2.csproj", "{3E737796-3A83-4924-9FF1-DC542F21F59E}" -EndProject -Project("{CFEE4113-1246-4D54-95CB-156813CB8593}") = "ServiceInstall", "ServiceInstall\ServiceInstall.wixproj", "{1CBA8F74-050C-432B-8437-08BD13BDC684}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Console", "Console\Console.csproj", "{D09E6A1F-55F6-4661-8E5A-C485E4B08BB3}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrameworkInternal", "FrameworkInternal\FrameworkInternal.csproj", "{5B011775-B121-4EEE-A410-BA2D2F5BFB8B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BooScriptExecutorFactory", "BooScriptExecutorFactory\BooScriptExecutorFactory.csproj", "{0747C440-70E4-4E63-9F9D-03B3A010C991}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShellScriptExecutorFactory", "ShellScriptExecutorFactory\ShellScriptExecutorFactory.csproj", "{4700690A-2D29-40A0-86AC-E5A9F71A479A}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ActiveDirectoryConnector", "ActiveDirectoryConnector\ActiveDirectoryConnector.csproj", "{BDF495CA-0FCD-4E51-A871-D467CDE3B43E}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ActiveDirectoryConnectorTests", "ActiveDirectoryConnectorTests\ActiveDirectoryConnectorTests.csproj", "{DB8F7DA9-11A2-4BEB-8C14-25D8229EBE7E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestCommon", "TestCommon\TestCommon.csproj", "{E6A207D2-E083-41BF-B522-D9D3EC09323E}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A9D6374A-D51F-4FA3-8C02-5B1D23FAA82E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A9D6374A-D51F-4FA3-8C02-5B1D23FAA82E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A9D6374A-D51F-4FA3-8C02-5B1D23FAA82E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A9D6374A-D51F-4FA3-8C02-5B1D23FAA82E}.Release|Any CPU.Build.0 = Release|Any CPU - {8B24461B-456A-4032-89A1-CD418F7B5B62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8B24461B-456A-4032-89A1-CD418F7B5B62}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8B24461B-456A-4032-89A1-CD418F7B5B62}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8B24461B-456A-4032-89A1-CD418F7B5B62}.Release|Any CPU.Build.0 = Release|Any CPU - {F140E8DA-52B4-4159-992A-9DA10EA8EEFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F140E8DA-52B4-4159-992A-9DA10EA8EEFB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F140E8DA-52B4-4159-992A-9DA10EA8EEFB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F140E8DA-52B4-4159-992A-9DA10EA8EEFB}.Release|Any CPU.Build.0 = Release|Any CPU - {32804F5A-812C-4FA6-835C-BDAE5B24D355}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {32804F5A-812C-4FA6-835C-BDAE5B24D355}.Debug|Any CPU.Build.0 = Debug|Any CPU - {32804F5A-812C-4FA6-835C-BDAE5B24D355}.Release|Any CPU.ActiveCfg = Release|Any CPU - {32804F5A-812C-4FA6-835C-BDAE5B24D355}.Release|Any CPU.Build.0 = Release|Any CPU - {0BC2A013-56FE-46DD-90FC-2D2D57748FB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0BC2A013-56FE-46DD-90FC-2D2D57748FB6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0BC2A013-56FE-46DD-90FC-2D2D57748FB6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0BC2A013-56FE-46DD-90FC-2D2D57748FB6}.Release|Any CPU.Build.0 = Release|Any CPU - {3E737796-3A83-4924-9FF1-DC542F21F59E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3E737796-3A83-4924-9FF1-DC542F21F59E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3E737796-3A83-4924-9FF1-DC542F21F59E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3E737796-3A83-4924-9FF1-DC542F21F59E}.Release|Any CPU.Build.0 = Release|Any CPU - {1CBA8F74-050C-432B-8437-08BD13BDC684}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1CBA8F74-050C-432B-8437-08BD13BDC684}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1CBA8F74-050C-432B-8437-08BD13BDC684}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1CBA8F74-050C-432B-8437-08BD13BDC684}.Release|Any CPU.Build.0 = Release|Any CPU - {D09E6A1F-55F6-4661-8E5A-C485E4B08BB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D09E6A1F-55F6-4661-8E5A-C485E4B08BB3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D09E6A1F-55F6-4661-8E5A-C485E4B08BB3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D09E6A1F-55F6-4661-8E5A-C485E4B08BB3}.Release|Any CPU.Build.0 = Release|Any CPU - {5B011775-B121-4EEE-A410-BA2D2F5BFB8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5B011775-B121-4EEE-A410-BA2D2F5BFB8B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5B011775-B121-4EEE-A410-BA2D2F5BFB8B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5B011775-B121-4EEE-A410-BA2D2F5BFB8B}.Release|Any CPU.Build.0 = Release|Any CPU - {0747C440-70E4-4E63-9F9D-03B3A010C991}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0747C440-70E4-4E63-9F9D-03B3A010C991}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0747C440-70E4-4E63-9F9D-03B3A010C991}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0747C440-70E4-4E63-9F9D-03B3A010C991}.Release|Any CPU.Build.0 = Release|Any CPU - {4700690A-2D29-40A0-86AC-E5A9F71A479A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4700690A-2D29-40A0-86AC-E5A9F71A479A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4700690A-2D29-40A0-86AC-E5A9F71A479A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4700690A-2D29-40A0-86AC-E5A9F71A479A}.Release|Any CPU.Build.0 = Release|Any CPU {BDF495CA-0FCD-4E51-A871-D467CDE3B43E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BDF495CA-0FCD-4E51-A871-D467CDE3B43E}.Debug|Any CPU.Build.0 = Debug|Any CPU {BDF495CA-0FCD-4E51-A871-D467CDE3B43E}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -87,10 +18,6 @@ Global {DB8F7DA9-11A2-4BEB-8C14-25D8229EBE7E}.Debug|Any CPU.Build.0 = Debug|Any CPU {DB8F7DA9-11A2-4BEB-8C14-25D8229EBE7E}.Release|Any CPU.ActiveCfg = Release|Any CPU {DB8F7DA9-11A2-4BEB-8C14-25D8229EBE7E}.Release|Any CPU.Build.0 = Release|Any CPU - {E6A207D2-E083-41BF-B522-D9D3EC09323E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E6A207D2-E083-41BF-B522-D9D3EC09323E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E6A207D2-E083-41BF-B522-D9D3EC09323E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E6A207D2-E083-41BF-B522-D9D3EC09323E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ExchangeConnector/ExchangeConnector.csproj b/ExchangeConnector/ExchangeConnector.csproj index 4af39ff..7fa4ab2 100644 --- a/ExchangeConnector/ExchangeConnector.csproj +++ b/ExchangeConnector/ExchangeConnector.csproj @@ -35,6 +35,7 @@ v3.5 512 true + ..\..\framework\dotnet false ExchangeConnectorTests @@ -57,6 +58,16 @@ 4 + + False + $(ConnectorFrameworkDir)\Dist\Common.dll + False + + + False + $(ConnectorFrameworkDir)\Dist\Framework.dll + False + False @@ -80,16 +91,6 @@ ActiveDirectoryConnector True - - {F140E8DA-52B4-4159-992A-9DA10EA8EEFB} - Common - False - - - {8B24461B-456A-4032-89A1-CD418F7B5B62} - Framework - False - diff --git a/Framework/Api.cs b/Framework/Api.cs deleted file mode 100644 index af22550..0000000 --- a/Framework/Api.cs +++ /dev/null @@ -1,592 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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; -using System.Globalization; -using System.Collections.Generic; -using System.Net.Security; -using System.Security; -using System.Security.Cryptography.X509Certificates; -using System.Text; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Common.Pooling; -using Org.IdentityConnectors.Common.Security; -using Org.IdentityConnectors.Framework.Api.Operations; -using Org.IdentityConnectors.Framework.Common; -using Org.IdentityConnectors.Framework.Common.Objects; - -namespace Org.IdentityConnectors.Framework.Api -{ - public static class APIConstants - { - public const int NO_TIMEOUT = -1; - } - - public interface APIConfiguration - { - ConfigurationProperties ConfigurationProperties { get; } - bool IsConnectorPoolingSupported { get; } - ObjectPoolConfiguration ConnectorPoolConfiguration { get; } - ICollection> SupportedOperations { get; } - - int GetTimeout(SafeType operation); - void SetTimeout(SafeType operation, int timeout); - - int ProducerBufferSize { get; set; } - } - - /// - /// Configuration properties encapsulates the and uses - /// to determine the properties available for manipulation. - /// - public interface ConfigurationProperties - { - /// - /// Get the list of properties names for this . - /// - /// get the list of properties names. - IList PropertyNames { get; } - - /// - /// Get a particular by name. - /// - /// the unique name of the property. - /// a if it exists otherwise null. - ConfigurationProperty GetProperty(string name); - - /// - /// Set the value of the property by name. - /// - /// Name of the property to set the value against. - /// Value to set on the configuration property. - /// iff the property name does not exist. - void SetPropertyValue(string name, Object value); - - } - - /// - /// Translation from at the SPI layer to the API. - /// - public interface ConfigurationProperty - { - int Order { get; } - - /// - /// Get the unique name of the configuration property. - /// - string Name { get; } - - /// - /// Get the help message from the message catalog. - /// - string GetHelpMessage(string def); - - /// - /// Get the display name for the is configuration - /// - string GetDisplayName(string def); - - /// - /// Get the value from the property. - /// - /// - /// This should be the default value. - /// - object Value { get; set; } - - /// - /// Get the type of the property. - /// - Type ValueType { get; } - - /// - /// Is this a confidential property whose value should be encrypted by - /// the application when persisted? - /// - bool IsConfidential { get; } - - /// - /// Is this a required property - /// - /// True if the property is required - bool IsRequired { get; } - - /// - /// Set of operations for which this property must be specified. - /// - /// - /// This is used for the case where a connector may or may not - /// implement certain operations depending in the configuration. - /// The default value of "empty array" is special in that - /// it means that this property is applicable to all operations. - /// - /// - ICollection> Operations { get; } - } - - /// - /// Main interface for which consumers call the Connector API logic. - /// - public interface ConnectorFacade : CreateApiOp, DeleteApiOp, - SearchApiOp, UpdateApiOp, SchemaApiOp, AuthenticationApiOp, ResolveUsernameApiOp, - GetApiOp, ValidateApiOp, TestApiOp, ScriptOnConnectorApiOp, ScriptOnResourceApiOp, - SyncApiOp - { - /// - /// Get the set of operations that this will support. - /// - ICollection> SupportedOperations { get; } - - /// - /// Get an instance of an operation that this facade supports. - /// - APIOperation GetOperation(SafeType type); - - } - - /// - /// Manages a pool of connectors for use by a provisioner. - /// - public abstract class ConnectorFacadeFactory - { - // At some point we might make this pluggable, but for now, hard-code - private const string IMPL_NAME = - "Org.IdentityConnectors.Framework.Impl.Api.ConnectorFacadeFactoryImpl"; - private static ConnectorFacadeFactory _instance; - private static object LOCK = new Object(); - - /// - /// Get the singleton instance of the . - /// - public static ConnectorFacadeFactory GetInstance() - { - lock (LOCK) - { - if (_instance == null) - { - SafeType t = FrameworkInternalBridge.LoadType(IMPL_NAME); - _instance = t.CreateInstance(); - } - } - return _instance; - } - - /// - /// Get a new instance of . - /// - /// all the configuration that the framework, connector, and - /// pooling needs. - /// - /// to call API operations against. - /// - public abstract ConnectorFacade NewInstance(APIConfiguration config); - - - /// - /// Dispose of all connection pools, resources, etc. - /// - public abstract void Dispose(); - } - - /// - /// The connector meta-data for a given connector. - /// - public interface ConnectorInfo - { - /// - /// Returns a friendly name suitable for display in the UI. - /// - /// The friendly name - string GetConnectorDisplayName(); - - ConnectorMessages Messages { get; } - - ConnectorKey ConnectorKey { get; } - - /// - /// Loads the and class in order to - /// determine the proper default configuration parameters. - /// - APIConfiguration CreateDefaultAPIConfiguration(); - } - /// - /// Class responsible for maintaing a list of ConnectorInfo - /// associated with a set of connector bundles. - /// - public interface ConnectorInfoManager - { - /// - /// Returns the list of ConnectorInfo - /// - /// the list of ConnectorInfo - IList ConnectorInfos { get; } - - /// - /// Given a connectorName and connectorVersion, returns the - /// associated ConnectorInfo. - /// - /// The connector key. - /// The ConnectorInfo or null if it couldn't - /// be found. - ConnectorInfo FindConnectorInfo(ConnectorKey key); - } - /// - /// The main entry point into connectors. - /// - /// - /// This allows you - /// to load the connector classes from a set of bundles. - /// - public abstract class ConnectorInfoManagerFactory - { - //At some point we might make this pluggable, but for now, hard-code - private const string IMPL_NAME = - "Org.IdentityConnectors.Framework.Impl.Api.ConnectorInfoManagerFactoryImpl"; - private static ConnectorInfoManagerFactory _instance; - private static object LOCK = new Object(); - /// - /// Singleton pattern for getting an instance of the - /// ConnectorInfoManagerFactory. - /// - /// - public static ConnectorInfoManagerFactory GetInstance() - { - lock (LOCK) - { - if (_instance == null) - { - SafeType t = - FrameworkInternalBridge.LoadType(IMPL_NAME); - _instance = t.CreateInstance(); - } - } - return _instance; - } - public abstract ConnectorInfoManager GetLocalManager(); - public abstract ConnectorInfoManager GetRemoteManager(RemoteFrameworkConnectionInfo info); - - /// - /// Clears the bundle manager cache. - /// - /// - /// Generally intended for unit testing - /// - public abstract void ClearRemoteCache(); - } - - /// - /// Uniquely identifies a connector within an installation. - /// - /// - /// Consists of the triple (bundleName, bundleVersion, connectorName) - /// - public sealed class ConnectorKey - { - private readonly string _bundleName; - private readonly string _bundleVersion; - private readonly string _connectorName; - - public ConnectorKey(String bundleName, - String bundleVersion, - String connectorName) - { - if (bundleName == null) - { - throw new ArgumentException("bundleName may not be null"); - } - if (bundleVersion == null) - { - throw new ArgumentException("bundleVersion may not be null"); - } - if (connectorName == null) - { - throw new ArgumentException("connectorName may not be null"); - } - _bundleName = bundleName; - _bundleVersion = bundleVersion; - _connectorName = connectorName; - } - - public string BundleName - { - get - { - return _bundleName; - } - } - - public string BundleVersion - { - get - { - return _bundleVersion; - } - } - - public string ConnectorName - { - get - { - return _connectorName; - } - } - - public override bool Equals(object o) - { - if (o is ConnectorKey) - { - ConnectorKey other = (ConnectorKey)o; - if (!_bundleName.Equals(other._bundleName)) - { - return false; - } - if (!_bundleVersion.Equals(other._bundleVersion)) - { - return false; - } - if (!_connectorName.Equals(other._connectorName)) - { - return false; - } - return true; - } - return false; - } - - public override int GetHashCode() - { - int rv = 0; - rv ^= _connectorName.GetHashCode(); - return rv; - } - - public override string ToString() - { - StringBuilder builder = new StringBuilder(); - builder.Append("ConnectorKey("); - builder.Append(" bundleName=").Append(_bundleName); - builder.Append(" bundleVersion=").Append(_bundleVersion); - builder.Append(" connectorName=").Append(_connectorName); - builder.Append(" )"); - return builder.ToString(); - } - } - - - - public sealed class RemoteFrameworkConnectionInfo - { - private readonly String _host; - private readonly int _port; - private readonly GuardedString _key; - private readonly bool _useSSL; - private readonly RemoteCertificateValidationCallback _certificateValidationCallback; - private readonly int _timeout; - - /// - /// Creates a new instance of RemoteFrameworkConnectionInfo, using - /// a clear (non-ssl) connection and a 60-second timeout. - /// - /// The host to connect to - /// The port to connect to - public RemoteFrameworkConnectionInfo(String host, - int port, - GuardedString key) - : this(host, port, key, false, null, 60 * 1000) - { - } - - /// - /// Creates a new instance of RemoteFrameworkConnectionInfo. - /// - /// The host to connect to - /// The port to connect to - /// Set to true if we are to connect via SSL. - /// to use - /// for establising the SSL connection. May be null or empty, - /// in which case the default installed providers for the JVM will - /// be used. Ignored if 'useSSL' is false. - /// The timeout to use (in milliseconds). A value of 0 - /// means infinite timeout; - public RemoteFrameworkConnectionInfo(String host, - int port, - GuardedString key, - bool useSSL, - RemoteCertificateValidationCallback certificateValidationCallback, - int timeout) - { - - if (host == null) - { - throw new ArgumentException("Parameter 'host' is null."); - } - if (key == null) - { - throw new ArgumentException("Parameter 'key' is null."); - } - - _host = host; - _port = port; - _key = key; - _useSSL = useSSL; - _certificateValidationCallback = certificateValidationCallback; - _timeout = timeout; - } - - /// - /// Returns the host to connect to. - /// - /// The host to connect to. - public String Host - { - get - { - return _host; - } - } - - /// - /// Returns the port to connect to - /// - /// The port to connect to - public int Port - { - get - { - return _port; - } - } - - public GuardedString Key - { - get - { - return _key; - } - } - - /// - /// Returns true iff we are to use SSL to connect. - /// - /// true iff we are to use SSL to connect. - public bool UseSSL - { - get - { - return _useSSL; - } - } - - /// - /// Returns the list of 's. - /// - /// - /// to use when establishing - /// the connection. - /// - /// The list of 's. - public RemoteCertificateValidationCallback CertificateValidationCallback - { - get - { - return _certificateValidationCallback; - } - } - - /// - /// Returns the timeout (in milliseconds) to use for the connection. - /// - /// - /// A value of zero means infinite timeout. - /// - /// the timeout (in milliseconds) to use for the connection. - public int Timeout - { - get - { - return _timeout; - } - } - - public override bool Equals(Object o) - { - if (o is RemoteFrameworkConnectionInfo) - { - RemoteFrameworkConnectionInfo other = - (RemoteFrameworkConnectionInfo)o; - if (!Object.Equals(Host, other.Host)) - { - return false; - } - if (Port != other.Port) - { - return false; - } - if (UseSSL != other.UseSSL) - { - return false; - } - if (CertificateValidationCallback == null || - other.CertificateValidationCallback == null) - { - if (CertificateValidationCallback != null || - other.CertificateValidationCallback != null) - { - return false; - } - } - else - { - if (!CertificateValidationCallback.Equals - (other.CertificateValidationCallback)) - { - return false; - } - } - - if (!Key.Equals(other.Key)) - { - return false; - } - - if (Timeout != other.Timeout) - { - return false; - } - - return true; - } - return false; - } - - public override int GetHashCode() - { - return _host.GetHashCode() ^ _port; - } - - public override String ToString() - { - return "{host=" + _host + ", port=" + _port + "}"; - } - } -} diff --git a/Framework/ApiOperations.cs b/Framework/ApiOperations.cs deleted file mode 100644 index 0af94b6..0000000 --- a/Framework/ApiOperations.cs +++ /dev/null @@ -1,470 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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; -using System.Globalization; -using System.Collections.Generic; - -using Org.IdentityConnectors.Common.Security; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Common.Objects.Filters; - -namespace Org.IdentityConnectors.Framework.Api.Operations -{ - /// - /// Base interface for all API operations. - /// - public interface APIOperation - { - } - - public interface AuthenticationApiOp : APIOperation - { - /// - /// Most basic authentication available. - /// - /// string that represents the account or user id. - /// string that represents the password for the account or user. - /// iff the credentials do not pass authentication otherwise - /// nothing. - Uid Authenticate(ObjectClass objectClass, string username, GuardedString password, OperationOptions options); - } - - public interface ResolveUsernameApiOp : APIOperation - { - /// - /// Resolve the given username - /// to the corresponding . - /// - /// - /// The Uid is the one - /// that would return - /// in case of a successful authentication. - /// - /// The object class to use for authenticate. - /// Will typically be an account. Must not be null. - /// string that represents the account or user id. - /// additional options that impact the way this operation is run. - /// May be null. - /// Uid The uid of the account that would be used to authenticate. - /// iff the username could not be resolved. - Uid ResolveUsername(ObjectClass objectClass, string username, OperationOptions options); - } - - /// - /// Operation to create connector objects based on the attributes provided. - /// - public interface CreateApiOp : APIOperation - { - /// - /// Creates a user based on the ConnectorAttributes provide. The only - /// required attribute is the ObjectClass and those required by the - /// Connector. The API will validate the existence of the - /// ObjectClass attribute and that there are no duplicate name'd - /// attributes. - /// - /// ConnectorAttribtes to create the object. - /// Unique id for the created object. - Uid Create(ObjectClass oclass, ICollection attrs, OperationOptions options); - } - - /// - /// Deletes an object with the specified Uid and ObjectClass on the - /// resource. - /// - public interface DeleteApiOp : APIOperation - { - /// - /// Delete the object that the specified Uid identifies (if any). - /// - /// The type of object to delete. - /// The unique identitfier for the object to delete. - /// Throws UnknowUid if the object does not exist. - void Delete(ObjectClass objectClass, Uid uid, OperationOptions options); - } - - /// - /// Get a particular based on the . - /// - public interface GetApiOp : APIOperation - { - /// - /// Get a particular based on the . - /// - /// the unique id of the object that to get. - /// - /// based on the provided. - ConnectorObject GetObject(ObjectClass objClass, Uid uid, OperationOptions options); - } - - /// - /// Get the schema from the . - /// - public interface SchemaApiOp : APIOperation - { - /// - /// Retrieve the basic schema of this . - /// - Schema Schema(); - } - - - public interface SearchApiOp : APIOperation - { - /// - /// Search the resource for all objects that match the filter. - /// - /// Reduces the number of entries to only those that match the - /// provided. - /// class responsible for working with the objects returned from - /// the search. - /// iff there is problem during the processing of the results. - void Search(ObjectClass oclass, Filter filter, ResultsHandler handler, OperationOptions options); - } - - /// - /// Runs a script in the same JVM or .Net Runtime as the Connector. - /// - /// - /// That is, if you are using a local framework, the script will be - /// run in your JVM. If you are connected to a remote framework, the - /// script will be run in the remote JVM or .Net Runtime. - /// - /// This API allows an application to run a script in the context - /// of any connector. (A connector need not implement any particular interface - /// in order to enable this.) The minimum contract to which each connector - /// must adhere is as follows: - /// - /// - /// Script will run in the same classloader/execution environment - /// as the connector, so the script will have access to all the classes - /// to which the connector has access. - /// - /// - /// - /// Script will have access to a "connector" variable - /// that is equivalent to an initialized instance of a connector. - /// Thus, at a minimum the script will be able to access - /// . - /// - /// - /// - /// Script will have access to any - /// - /// passed in by the application. - /// - /// - /// - /// - /// - /// A connector that implements - /// may provide more variables than what is described above. - /// A connector also may perform special processing - /// for specific to that connector. - /// Consult the javadoc of each particular connector to find out what - /// additional capabilities, if any, that connector exposes for use in scripts. - /// - /// - /// NOTE: A caller who wants to execute scripts on a connector - /// should assume that a script must not use any method of the connector - /// beyond the minimum contract described above, - /// unless the connector explicitly documents that method as - /// "for use by connector script". The primary function of a connector - /// is to implement the SPI in the context of the Connector framework. - /// In general, no caller should invoke Connector methods directly - /// --whether by a script or by other means. - /// - /// - public interface ScriptOnConnectorApiOp : APIOperation - { - /// - /// Runs the script. - /// - /// - The script and arguments to run. - /// - Additional options that control how the script is - /// run. The framework does not currently recognize any options - /// but specific connectors might. Consult the documentation - /// for each connector to identify supported options. - /// The result of the script. The return type must be - /// a type that the framework supports for serialization. - /// - Object RunScriptOnConnector(ScriptContext request, - OperationOptions options); - } - /// - /// Runs a script on the target resource that a connector manages. - /// - /// - /// This API operation is supported only for a connector that implements - /// . - /// - /// The contract here at the API level is intentionally very loose. - /// Each connector decides what script languages it supports, - /// what running a script on a target resource actually means, - /// and what script options (if any) that connector supports. - /// Refer to the javadoc of each particular connector for more information. - /// - /// - public interface ScriptOnResourceApiOp : APIOperation - { - /// - /// Runs a script on a specific target resource. - /// - /// The script and arguments to run. - /// Additional options which control how the script is - /// run. Please refer to the connector documentation for supported - /// options. - /// The result of the script. The return type must be - /// a type that the connector framework supports for serialization. - /// See for a list of supported return types. - Object RunScriptOnResource(ScriptContext request, - OperationOptions options); - } - /// - /// Receive synchronization events from the resource. - /// - /// - /// This will be supported by - /// connectors that implement . - /// - /// - public interface SyncApiOp : APIOperation - { - /// - /// Perform a synchronization. - /// - /// The object class to synchronize. Must not be null. - /// The token representing the last token from the previous sync. - /// Should be null if this is the first sync for the given - /// resource. - /// The result handler Must not be null. - /// additional options that impact the way this operation is run. - /// May be null. - void Sync(ObjectClass objClass, SyncToken token, - SyncResultsHandler handler, - OperationOptions options); - /// - /// Returns the token corresponding to the latest sync delta. - /// - /// - /// This is to support applications that may wish to sync starting - /// "now". - /// - /// The latest token or null if there is no sync data. - SyncToken GetLatestSyncToken(ObjectClass objectClass); - } - - /// - /// Updates a . - /// - /// - /// This operation - /// is supported for those connectors that implement - /// either or the more advanced - /// . - /// - public interface UpdateApiOp : APIOperation - { - /// - /// Update the object specified by the and , - /// replacing the current values of each attribute with the values - /// provided. - /// - /// - /// - /// For each input attribute, replace - /// all of the current values of that attribute in the target object with - /// the values of that attribute. - /// - /// - /// If the target object does not currently contain an attribute that the - /// input set contains, then add this - /// attribute (along with the provided values) to the target object. - /// - /// - /// If the value of an attribute in the input set is - /// null, then do one of the following, depending on - /// which is most appropriate for the target: - /// - /// - /// If possible, remove that attribute from the target - /// object entirely. - /// - /// - /// - /// Otherwise, replace all of the current values of that - /// attribute in the target object with a single value of - /// null. - /// - /// - /// - /// - /// - /// the type of object to modify. Must not be null. - /// the uid of the object to modify. Must not be null. - /// set of new . the values in this set - /// represent the new, merged values to be applied to the object. - /// This set may also include . - /// Must not be null. - /// additional options that impact the way this operation is run. - /// May be null. - /// the of the updated object in case the update changes - /// the formation of the unique identifier. - /// iff the does not exist on the resource. - Uid Update(ObjectClass objclass, - Uid uid, - ICollection replaceAttributes, - OperationOptions options); - - /// - /// Update the object specified by the and , - /// adding to the current values of each attribute the values provided. - /// - /// - /// - /// For each attribute that the input set contains, add to - /// the current values of that attribute in the target object all of the - /// values of that attribute in the input set. - /// - /// - /// NOTE that this does not specify how to handle duplicate values. - /// The general assumption for an attribute of a ConnectorObject - /// is that the values for an attribute may contain duplicates. - /// Therefore, in general simply append the provided values - /// to the current value for each attribute. - /// - /// - /// IMPLEMENTATION NOTE: for connectors that merely implement - /// and not this method will be simulated by - /// fetching, merging, and calling - /// . Therefore, - /// connector implementations are encourage to implement - /// from a performance and atomicity standpoint. - /// - /// - /// the type of object to modify. Must not be null. - /// the uid of the object to modify. Must not be null. - /// set of deltas. The values for the attributes - /// in this set represent the values to add to attributes in the object. - /// merged. This set must not include . - /// Must not be null. - /// additional options that impact the way this operation is run. - /// May be null. - /// the of the updated object in case the update changes - /// the formation of the unique identifier. - /// iff the does not exist on the resource. - Uid AddAttributeValues(ObjectClass objclass, - Uid uid, - ICollection valuesToAdd, - OperationOptions options); - - /// - /// Update the object specified by the and , - /// removing from the current values of each attribute the values provided. - /// - /// - /// - /// For each attribute that the input set contains, - /// remove from the current values of that attribute in the target object - /// any value that matches one of the values of the attribute from the input set. - /// - /// - /// NOTE that this does not specify how to handle unmatched values. - /// The general assumption for an attribute of a ConnectorObject - /// is that the values for an attribute are merely representational state. - /// Therefore, the implementer should simply ignore any provided value - /// that does not match a current value of that attribute in the target - /// object. Deleting an unmatched value should always succeed. - /// - /// - /// IMPLEMENTATION NOTE: for connectors that merely implement - /// and not this method will be simulated by - /// fetching, merging, and calling - /// . Therefore, - /// connector implementations are encourage to implement - /// from a performance and atomicity standpoint. - /// - /// - /// the type of object to modify. Must not be null. - /// the uid of the object to modify. Must not be null. - /// set of deltas. The values for the attributes - /// in this set represent the values to remove from attributes in the object. - /// merged. This set must not include . - /// Must not be null. - /// additional options that impact the way this operation is run. - /// May be null. - /// the of the updated object in case the update changes - /// the formation of the unique identifier. - /// iff the does not exist on the resource. - Uid RemoveAttributeValues(ObjectClass objclass, - Uid uid, - ICollection valuesToRemove, - OperationOptions options); - - } - - /// - /// Validates the . - /// - /// A valid configuration is one that is ready to be used by the connector: - /// it is complete (all the required properties have been given values) - /// and the property values are well-formed (are in the expected range, - /// have the expected format, etc.) - /// - public interface ValidateApiOp : APIOperation - { - /// - /// Validates the . - /// - /// iff the configuration is not valid. - void Validate(); - } - - /// - /// Tests the with the connector. - /// - /// Unlike validation performed by , testing a configuration should - /// check that any pieces of environment referred by the configuration are available. - /// For example the connector could make a physical connection to a host specified - /// in the configuration to check that it exists and that the credentials - /// specified in the configuration are usable. - /// - /// - /// Since this operation may connect to the resource, it may be slow. Clients are - /// advised not to invoke this operation often, such as before every provisioning operation. - /// This operation is not intended to check that the connector is alive - /// (i.e., its physical connection to the resource has not timed out). - /// - /// - /// This operation may be invoked before the configuration has been validated. - /// - /// - public interface TestApiOp : APIOperation - { - /// - /// Tests the current with the connector. - /// - /// iff the configuration is not valid or the test failed. - void Test(); - } -} \ No newline at end of file diff --git a/Framework/Common.cs b/Framework/Common.cs deleted file mode 100644 index 47d1b6c..0000000 --- a/Framework/Common.cs +++ /dev/null @@ -1,382 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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; -using System.Collections.Generic; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Common.Security; -using Org.IdentityConnectors.Framework.Spi; -using Org.IdentityConnectors.Framework.Api.Operations; -using Org.IdentityConnectors.Framework.Spi.Operations; -using Org.IdentityConnectors.Framework.Common.Objects; -namespace Org.IdentityConnectors.Framework.Common -{ - 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 SafeType LoadType(String typeName) where T : class - { - - Assembly assembly; - lock (LOCK) - { - if (_assembly == null) - { - AssemblyName assemName = new AssemblyName(); - assemName.Name = "FrameworkInternal"; - _assembly = Assembly.Load(assemName); - } - assembly = _assembly; - } - - return SafeType.ForRawType(assembly.GetType(typeName, true)); - - } - } - - public static class FrameworkUtil - { - private static readonly IDictionary, SafeType> SPI_TO_API; - private static readonly ICollection CONFIG_SUPPORTED_TYPES; - private static readonly ICollection ATTR_SUPPORTED_TYPES; - - static FrameworkUtil() - { - IDictionary, SafeType> temp = - new Dictionary, SafeType>(); - temp[SafeType.Get()] = - SafeType.Get(); - temp[SafeType.Get()] = - SafeType.Get(); - temp[SafeType.Get()] = - SafeType.Get(); - temp[SafeType.Get()] = - SafeType.Get(); - temp[SafeType.ForRawType(typeof(SearchOp<>))] = - SafeType.Get(); - temp[SafeType.Get()] = - SafeType.Get(); - temp[SafeType.Get()] = - SafeType.Get(); - temp[SafeType.Get()] = - SafeType.Get(); - temp[SafeType.Get()] = - SafeType.Get(); - temp[SafeType.Get()] = - SafeType.Get(); - temp[SafeType.Get()] = - SafeType.Get(); - temp[SafeType.Get()] = - SafeType.Get(); - SPI_TO_API = CollectionUtil.NewReadOnlyDictionary(temp); - - CONFIG_SUPPORTED_TYPES = CollectionUtil.NewReadOnlySet - ( - typeof(string), - typeof(long), - typeof(long?), - typeof(char), - typeof(char?), - typeof(double), - typeof(double?), - typeof(float), - typeof(float?), - typeof(int), - typeof(int?), - typeof(bool), - typeof(bool?), - typeof(Uri), - typeof(FileName), - typeof(GuardedByteArray), - typeof(GuardedString), - typeof(Script) - ); - ATTR_SUPPORTED_TYPES = CollectionUtil.NewReadOnlySet - ( - typeof(string), - typeof(long), - typeof(long?), - typeof(char), - typeof(char?), - typeof(double), - typeof(double?), - typeof(float), - typeof(float?), - typeof(int), - typeof(int?), - typeof(bool), - typeof(bool?), - typeof(byte[]), - typeof(BigDecimal), - typeof(BigInteger), - typeof(GuardedByteArray), - typeof(GuardedString) - ); - - } - - - /// - /// Determines if the class is a supported attribute type. - /// - /// - /// If not it throws - /// an . - /// - /// - /// string - /// - /// - /// - /// long - /// - /// - /// - /// long? - /// - /// - /// - /// char - /// - /// - /// - /// char? - /// - /// - /// - /// double - /// - /// - /// - /// double? - /// - /// - /// - /// float - /// - /// - /// - /// float? - /// - /// - /// - /// int - /// - /// - /// - /// int? - /// - /// - /// - /// bool - /// - /// - /// - /// bool? - /// - /// - /// - /// byte[] - /// - /// - /// - /// BigDecimal - /// - /// - /// - /// BigInteger - /// - /// - /// - /// - /// type to check against the support list of types. - /// iff the type is not on the supported list. - public static void CheckAttributeType(Type type) - { - if (!FrameworkUtil.IsSupportedAttributeType(type)) - { - String MSG = "Attribute type ''" + type + "'' is not supported."; - throw new ArgumentException(MSG); - } - } - public static void CheckAttributeValue(Object value) - { - if (value != null) - { - CheckAttributeType(value.GetType()); - } - } - public static ICollection> Spi2Apis(SafeType type) - { - type = type.GetTypeErasure(); - HashSet> set = new HashSet>(); - set.Add(SPI_TO_API[type]); - // add GetApiOp if search is available.. - - if (type.RawType.Equals(typeof(SearchOp<>))) - { - set.Add(SafeType.Get()); - } - return set; - } - public static ICollection> AllSPIOperations() - { - return SPI_TO_API.Keys; - } - public static ICollection> AllAPIOperations() - { - ICollection> set = - new HashSet>(); - CollectionUtil.AddAll(set, - SPI_TO_API.Values); - // add Get because it doesn't have a corresponding SPI. - set.Add(SafeType.Get()); - set.Add(SafeType.Get()); - return CollectionUtil.AsReadOnlySet(set); - } - public static ICollection> GetDefaultSupportedOperations(SafeType connector) - { - ICollection> rv = - new HashSet>(); - ICollection interfaces = - ReflectionUtil.GetTypeErasure(ReflectionUtil.GetAllInterfaces(connector.RawType)); - foreach (SafeType spi in AllSPIOperations()) - { - if (interfaces.Contains(spi.RawType)) - { - CollectionUtil.AddAll(rv, Spi2Apis(spi)); - } - } - //finally add unconditionally supported ops - CollectionUtil.AddAll(rv, GetUnconditionallySupportedOperations()); - return CollectionUtil.AsReadOnlySet(rv); - } - public static ICollection> GetUnconditionallySupportedOperations() - { - HashSet> ret; - ret = new HashSet>(); - //add validate api op always - ret.Add(SafeType.Get()); - //add ScriptOnConnectorApiOp always - ret.Add(SafeType.Get()); - return ret; - } - public static ICollection GetAllSupportedConfigTypes() - { - return CONFIG_SUPPORTED_TYPES; - } - public static bool IsSupportedConfigurationType(Type type) - { - if (type.IsArray) - { - return IsSupportedConfigurationType(type.GetElementType()); - } - else - { - return CONFIG_SUPPORTED_TYPES.Contains(type); - } - } - public static ICollection GetAllSupportedAttributeTypes() - { - return ATTR_SUPPORTED_TYPES; - } - public static bool IsSupportedAttributeType(Type clazz) - { - return ATTR_SUPPORTED_TYPES.Contains(clazz); - } - - /// - /// Determines if the class is a supported type for an OperationOption. - /// - /// - /// If not it throws - /// an . - /// - /// type to check against the support list of types. - /// iff the type is not on the supported list. - public static void CheckOperationOptionType(Type clazz) - { - //the set of supported operation option types - //is the same as that for configuration beans plus Name, - //ObjectClass, Uid, and QualifiedUid - - if (clazz.IsArray) - { - CheckOperationOptionType(clazz.GetElementType()); - return; - } - - if (FrameworkUtil.IsSupportedConfigurationType(clazz)) - { - return; //ok - } - - if (typeof(ObjectClass).IsAssignableFrom(clazz)) - { - return; //ok - } - - if (typeof(Uid).IsAssignableFrom(clazz)) - { - return; //ok - } - - if (typeof(QualifiedUid).IsAssignableFrom(clazz)) - { - return; //ok - } - - String MSG = "ConfigurationOption type '+" + clazz.Name + "+' is not supported."; - throw new ArgumentException(MSG); - } - /// - /// Determines if the class of the object is a supported attribute type. - /// - /// - /// If not it throws an . - /// - /// The value to check or null. - public static void CheckOperationOptionValue(Object val) - { - if (val != null) - { - CheckOperationOptionType(val.GetType()); - } - } - - /// - /// Returns the version of the framework. - /// - /// the framework version; never null. - public static Version GetFrameworkVersion() - { - return Assembly.GetExecutingAssembly().GetName().Version; - } - } -} \ No newline at end of file diff --git a/Framework/CommonExceptions.cs b/Framework/CommonExceptions.cs deleted file mode 100644 index 911bdf1..0000000 --- a/Framework/CommonExceptions.cs +++ /dev/null @@ -1,392 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 Org.IdentityConnectors.Framework.Common.Objects; - -namespace Org.IdentityConnectors.Framework.Common.Exceptions -{ - #region AlreadyExistsException - public class AlreadyExistsException : ConnectorException - { - public AlreadyExistsException() - : base() - { - } - - public AlreadyExistsException(String message) - : base(message) - { - - } - - public AlreadyExistsException(Exception ex) - : base(ex) - { - } - - public AlreadyExistsException(String message, Exception ex) - : base(message, ex) - { - } - } - #endregion - - #region ConfigurationException - public class ConfigurationException : ConnectorException - { - public ConfigurationException() - : base() - { - } - - public ConfigurationException(String message) - : base(message) - { - } - - public ConfigurationException(Exception ex) - : base(ex) - { - } - - public ConfigurationException(String message, Exception ex) - : base(message, ex) - { - } - } - #endregion - - #region ConnectionBrokenException - public class ConnectionBrokenException : ConnectorIOException - { - public ConnectionBrokenException() - : base() - { - } - - public ConnectionBrokenException(String msg) - : base(msg) - { - } - - public ConnectionBrokenException(Exception ex) - : base(ex) - { - } - - public ConnectionBrokenException(String message, Exception ex) - : base(message, ex) - { - } - } - #endregion - - #region ConnectionFailedException - public class ConnectionFailedException : ConnectorIOException - { - public ConnectionFailedException() - : base() - { - } - - public ConnectionFailedException(String msg) - : base(msg) - { - } - - public ConnectionFailedException(Exception ex) - : base(ex) - { - } - - public ConnectionFailedException(String message, Exception ex) - : base(message, ex) - { - } - - } - #endregion - - #region ConnectorException - public class ConnectorException : ApplicationException - { - public ConnectorException() - : base() - { - } - - /// - /// Sets a message for the . - /// - /// passed to the message. - public ConnectorException(String message) - : base(message) - { - } - - /// - /// Sets the stack trace to the original exception, so this exception can - /// masquerade as the original only be a . - /// - /// the original exception adapted to . - public ConnectorException(Exception ex) - : base(ex.Message, ex) - { - } - - /// - /// Sets the stack trace to the original exception, so this exception can - /// masquerade as the original only be a . - /// - /// - /// the original exception adapted to . - public ConnectorException(String message, Exception originalException) - : base(message, originalException) - { - } - - } - #endregion - - #region ConnectorIOException - public class ConnectorIOException : ConnectorException - { - public ConnectorIOException() - : base() - { - } - - public ConnectorIOException(String msg) - : base(msg) - { - } - - public ConnectorIOException(Exception ex) - : base(ex) - { - } - - public ConnectorIOException(String message, Exception ex) - : base(message, ex) - { - } - } - #endregion - - #region ConnectorSecurityException - public class ConnectorSecurityException : ConnectorException - { - public ConnectorSecurityException() - : base() - { - } - - public ConnectorSecurityException(String message) - : base(message) - { - } - - public ConnectorSecurityException(Exception ex) - : base(ex) - { - } - - public ConnectorSecurityException(String message, Exception ex) - : base(message, ex) - { - } - } - #endregion - - #region InvalidCredentialException - public class InvalidCredentialException : ConnectorSecurityException - { - public InvalidCredentialException() - : base() - { - } - - public InvalidCredentialException(String message) - : base(message) - { - } - - public InvalidCredentialException(Exception ex) - : base(ex) - { - } - - public InvalidCredentialException(String message, Exception ex) - : base(message, ex) - { - } - } - #endregion - - #region InvalidPasswordException - public class InvalidPasswordException : InvalidCredentialException - { - public InvalidPasswordException() - : base() - { - } - - public InvalidPasswordException(String message) - : base(message) - { - } - - public InvalidPasswordException(Exception ex) - : base(ex) - { - } - - public InvalidPasswordException(String message, Exception ex) - : base(message, ex) - { - } - } - #endregion - - #region OperationTimeoutException - public class OperationTimeoutException : ConnectorException - { - public OperationTimeoutException() - : base() - { - } - - public OperationTimeoutException(String msg) - : base(msg) - { - } - - public OperationTimeoutException(Exception e) - : base(e) - { - } - - public OperationTimeoutException(String msg, Exception e) - : base(msg, e) - { - } - - } - #endregion - - #region PasswordExpiredException - public class PasswordExpiredException : InvalidPasswordException - { - private Uid _uid; - - public PasswordExpiredException() - : base() - { - } - - public PasswordExpiredException(String message) - : base(message) - { - } - - public PasswordExpiredException(Exception ex) - : base(ex) - { - } - - public PasswordExpiredException(String message, Exception ex) - : base(message, ex) - { - } - - public Uid Uid - { - get - { - return _uid; - } - set - { - _uid = value; - } - } - } - #endregion - - #region PermissionDeniedException - public class PermissionDeniedException : ConnectorSecurityException - { - public PermissionDeniedException() - : base() - { - } - - public PermissionDeniedException(String message) - : base(message) - { - } - - public PermissionDeniedException(Exception ex) - : base(ex) - { - } - - public PermissionDeniedException(String message, Exception ex) - : base(message, ex) - { - } - } - #endregion - - #region UnknownUidException - public class UnknownUidException : InvalidCredentialException - { - const string MSG = "Object with Uid '{0}' and ObjectClass '{1}' does not exist!"; - - public UnknownUidException() - : base() - { - } - - public UnknownUidException(Uid uid, ObjectClass objclass) : - base(String.Format(MSG, uid, objclass)) - { - } - - public UnknownUidException(String message) - : base(message) - { - } - - public UnknownUidException(Exception ex) - : base(ex) - { - } - - public UnknownUidException(String message, Exception ex) - : base(message, ex) - { - } - } - #endregion -} \ No newline at end of file diff --git a/Framework/CommonObjects.cs b/Framework/CommonObjects.cs deleted file mode 100644 index 7607598..0000000 --- a/Framework/CommonObjects.cs +++ /dev/null @@ -1,4849 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Security; -using System.Collections; -using System.Collections.Generic; -using System.Globalization; -using System.Text; - -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Common.Security; - -using Org.IdentityConnectors.Framework.Spi; -using Org.IdentityConnectors.Framework.Spi.Operations; -using Org.IdentityConnectors.Framework.Api.Operations; -using Org.IdentityConnectors.Framework.Common.Serializer; -using Org.IdentityConnectors.Framework.Common.Objects.Filters; -namespace Org.IdentityConnectors.Framework.Common.Objects -{ - #region NameUtil - internal static class NameUtil - { - public static bool IsSpecialName(String name) - { - return (name.StartsWith("__") && name.EndsWith("__")); - } - - public static string CreateSpecialName(string name) - { - if (StringUtil.IsBlank(name)) - { - const string ERR = "Name parameter must not be blank!"; - throw new ArgumentException(ERR); - } - return "__" + name + "__"; - } - - public static bool NamesEqual(string name1, string name2) - { - return name1.ToUpper(CultureInfoCache.Instance).Equals( - name2.ToUpper(CultureInfoCache.Instance)); - } - - public static int GetNameHashCode(string name) - { - return name.ToUpper(CultureInfoCache.Instance).GetHashCode(); - } - } - #endregion - - #region ConnectorAttributeUtil - public static class ConnectorAttributeUtil - { - /// - /// Gets the string value from the single value attribute. - /// - /// ConnectorAttribute to retrieve the string value from. - /// null if the value is null otherwise the string value for the - /// attribute. - /// iff the object in the attribute is not an string. - /// iff the attribute is a multi valued instead of single valued. - public static string GetStringValue(ConnectorAttribute attr) - { - return (string)GetSingleValue(attr); - } - - /// - /// Gets the string value from the single value attribute. - /// - /// ConnectorAttribute to retrieve the string value from. - /// null if the value is null otherwise the string value for the - /// attribute. - /// iff the attribute is a multi valued instead of single valued. - public static string GetAsStringValue(ConnectorAttribute attr) - { - object obj = GetSingleValue(attr); - return obj != null ? obj.ToString() : null; - } - - public static GuardedString GetGuardedStringValue(ConnectorAttribute attr) - { - object obj = GetSingleValue(attr); - return obj != null ? (GuardedString)obj : null; - } - /// - /// Gets the integer value from the single value attribute. - /// - /// ConnectorAttribute to retrieve the integer value from. - /// null if the value is null otherwise the integer value for the - /// attribute. - /// iff the object in the attribute is not an integer. - /// iff the attribute is a multi valued instead of single valued. - public static int? GetIntegerValue(ConnectorAttribute attr) - { - object obj = GetSingleValue(attr); - return obj != null ? (int?)obj : null; - } - - /// - /// Gets the long value from the single value attribute. - /// - /// ConnectorAttribute to retrieve the long value from. - /// null if the value is null otherwise the long value for the - /// attribute. - /// iff the object in the attribute is not an long. - /// iff the attribute is a multi valued instead of single valued. - public static long? GetLongValue(ConnectorAttribute attr) - { - Object obj = GetSingleValue(attr); - return obj != null ? (long?)obj : null; - } - - /// - /// Gets the date value from the single value attribute. - /// - /// ConnectorAttribute to retrieve the date value from. - /// null if the value is null otherwise the date value for the - /// attribute. - /// iff the object in the attribute is not an long. - /// iff the attribute is a multi valued instead of single valued. - public static DateTime? GetDateTimeValue(ConnectorAttribute attr) - { - long? val = GetLongValue(attr); - if (val != null) - { - return DateTimeUtil.GetDateTimeFromUtcMillis(val.Value); - } - return null; - } - - /// - /// Gets the integer value from the single value attribute. - /// - /// ConnectorAttribute to retrieve the integer value from. - /// null if the value is null otherwise the integer value for the - /// attribute. - /// iff the object in the attribute is not an integer. - /// iff the attribute is a multi valued instead of single valued. - public static double? GetDoubleValue(ConnectorAttribute attr) - { - Object obj = GetSingleValue(attr); - return obj != null ? (double?)obj : null; - } - - public static bool? GetBooleanValue(ConnectorAttribute attr) - { - object obj = GetSingleValue(attr); - return obj != null ? (bool?)obj : null; - } - - /// - /// Get the single value from the ConnectorAttribute. - /// - /// - /// Return - /// null if the attribute's list of values is null or empty. - /// - public static object GetSingleValue(ConnectorAttribute attr) - { - Object ret = null; - IList val = attr.Value; - if (val != null && val.Count > 0) - { - // make sure this only called for single value.. - if (val.Count > 1) - { - const string MSG = "The method is only for single value attributes."; - throw new ArgumentException(MSG); - } - ret = val[0]; - } - return ret; - } - - /// - /// Transform a Collection of ConnectorAttribute} instances into a {@link Map}. - /// The key to each element in the map is the name of an ConnectorAttribute. - /// The value of each element in the map is the ConnectorAttribute instance with that name. - /// - /// - /// - public static IDictionary ToMap( - ICollection attributes) - { - IDictionary ret = - new Dictionary( - StringComparer.OrdinalIgnoreCase); - foreach (ConnectorAttribute attr in attributes) - { - ret[attr.Name] = attr; - } - return ret; - } - - /// - /// Get the from the attribute set. - /// - /// set of s that may contain a . - /// null if the set does not contain a object the first - /// one found. - public static Uid GetUidAttribute(ICollection attrs) - { - return (Uid)Find(Uid.NAME, attrs); - } - - /// - /// Filters out all special attributes from the set. - /// - /// - /// These special attributes - /// include , etc.. - /// - /// set of s to filter out the operational and - /// default attributes. - /// a set that only contains plain attributes or empty. - public static ICollection GetBasicAttributes(ICollection attrs) - { - ICollection ret = new HashSet(); - foreach (ConnectorAttribute attr in attrs) - { - // note this is dangerous because we need to be consistent - // in the naming of special attributes. - if (!IsSpecial(attr)) - { - ret.Add(attr); - } - } - return ret; - } - - /// - /// Filter out any basic attributes from the specified set, leaving only - /// special attributes. - /// - /// - /// Special attributes include , , - /// and . - /// - /// set of s to filter out the basic attributes - /// a set that only contains special attributes or an empty set if - /// there are none. - public static ICollection GetSpecialAttributes(ICollection attrs) - { - ICollection ret = new HashSet(); - foreach (ConnectorAttribute attr in attrs) - { - if (IsSpecial(attr)) - { - ret.Add(attr); - } - } - return ret; - } - - /// - /// Returns a mutable copy of the original set with the uid attribute removed. - /// - /// The original set. Must not be null. - /// A mutable copy of the original set with the uid attribute removed. - public static ICollection FilterUid(ICollection attrs) - { - Assertions.NullCheck(attrs, "attrs"); - HashSet ret = new HashSet(); - foreach (ConnectorAttribute attr in attrs) - { - if (!(attr is Uid)) - { - ret.Add(attr); - } - } - return ret; - } - - /// - /// Returns a mutable copy of the original set with the uid attribute added. - /// - /// The original set. Must not be null. - /// The uid. Must not be null. - /// A mutable copy of the original set with the uid attribute added. - public static ICollection AddUid(ICollection attrs, Uid uid) - { - Assertions.NullCheck(attrs, "attrs"); - Assertions.NullCheck(uid, "uid"); - HashSet ret = new HashSet(attrs); - ret.Add(uid); - return ret; - } - - /// - /// Determines if this attribute is a special attribute. - /// - /// - /// to test for against. - /// true iff the attribute value is a , - /// , , or - /// . - /// iff the attribute parameter is null. - public static bool IsSpecial(ConnectorAttribute attr) - { - // note this is dangerous because we need to be consistent - // in the naming of special attributes. - String name = attr.Name; - return IsSpecialName(name); - } - - /// - /// Determines if this attribute is a special attribute. - /// - /// - /// to test for against. - /// true iff the attribute value is a , - /// , , or - /// . - /// iff the attribute parameter is null. - public static bool IsSpecial(ConnectorAttributeInfo attr) - { - String name = attr.Name; - return IsSpecialName(name); - } - - /// - /// Determines whether the specified attribute name is special in the - /// sense of . - /// - /// the name of the attribute to test - /// true iff the attribute name is special - public static bool IsSpecialName(String name) - { - return NameUtil.IsSpecialName(name); - } - - /// - /// Creates the special naming for operational type attributes. - /// - /// string to make special - /// name constructed for use as an operational attribute. - public static string CreateSpecialName(string name) - { - return NameUtil.CreateSpecialName(name); - } - - /// - /// Compares two attribute names for equality. - /// - /// the first attribute name - /// the second attribute name - /// true iff the two attribute names are equal - public static bool NamesEqual(string name1, string name2) - { - return NameUtil.NamesEqual(name2, name2); - } - - /// - /// Gets the 'Name' attribute from a set of ConnectorAttributes. - /// - /// set of attributes to search against. - /// the 'Name' attribute it if exsist otherwisenull - public static Name GetNameFromAttributes(ICollection attrs) - { - return (Name)Find(Name.NAME, attrs); - } - - - /// - /// Find the of the given name in the . - /// - /// - /// 's name to search for. - /// - /// of attribute to search. - /// - /// with the specified otherwise null. - public static ConnectorAttribute Find(string name, ICollection attrs) - { - Assertions.NullCheck(name, "name"); - ICollection attributes = CollectionUtil.NullAsEmpty(attrs); - foreach (ConnectorAttribute attr in attributes) - { - if (attr.Is(name)) - { - return attr; - } - } - return null; - } - /// - /// Get the password value from the provided set of s. - /// - public static GuardedString GetPasswordValue(ICollection attrs) - { - ConnectorAttribute pwd = Find(OperationalAttributes.PASSWORD_NAME, attrs); - return (pwd == null) ? null : GetGuardedStringValue(pwd); - } - - /// - /// Get the current password value from the provided set of s. - /// - /// Set of s that may contain the current password - /// - /// . - /// - /// null if it does not exist in the else - /// the value. - public static GuardedString GetCurrentPasswordValue(ICollection attrs) - { - ConnectorAttribute pwd = Find(OperationalAttributes.CURRENT_PASSWORD_NAME, attrs); - return (pwd == null) ? null : GetGuardedStringValue(pwd); - } - /// - /// Determine if the is locked out. - /// - /// - /// By getting the - /// value of the . - /// - /// - /// object to inspect. - /// iff the parameter 'obj' is null. - /// - /// null if the attribute does not exist otherwise to - /// value of the . - public static bool? IsLockedOut(ConnectorObject obj) - { - ConnectorAttribute attr = obj.GetAttributeByName(OperationalAttributes.LOCK_OUT_NAME); - return (attr == null) ? null : GetBooleanValue(attr); - } - - /// - /// Determine if the is enable. - /// - /// - /// By getting the value - /// of the . - /// - /// - /// object to inspect. - /// if the object does not contain attribute in question. - /// iff the parameter 'obj' is null. - /// - /// null if the attribute does not exist otherwise to - /// value of the . - public static bool? IsEnabled(ConnectorObject obj) - { - ConnectorAttribute attr = obj.GetAttributeByName(OperationalAttributes.ENABLE_NAME); - return (attr == null) ? null : GetBooleanValue(attr); - } - - /// - /// Retrieve the password expiration date from the . - /// - /// - /// object to inspect. - /// if the object does not contain attribute in question. - /// iff the parameter 'obj' is null. - /// - /// null if the does not exist - /// otherwise the value of the . - public static DateTime? GetPasswordExpirationDate(ConnectorObject obj) - { - DateTime? ret = null; - ConnectorAttribute attr = obj.GetAttributeByName(OperationalAttributes.PASSWORD_EXPIRATION_DATE_NAME); - if (attr != null) - { - long? date = GetLongValue(attr); - if (date != null) - { - ret = DateTime.FromFileTimeUtc(date.Value); - } - } - return ret; - } - /// - /// Get the password expired attribute from a of - /// s. - /// - /// set of attribute to find the expired password - /// . - /// - /// null if the attribute does not exist and the value - /// of the if it does. - public static bool? GetPasswordExpired(ICollection attrs) - { - ConnectorAttribute pwd = Find(OperationalAttributes.PASSWORD_EXPIRED_NAME, attrs); - return (pwd == null) ? null : GetBooleanValue(pwd); - } - - /// - /// Determine if the password is expired for this object. - /// - /// - /// that should contain a password expired - /// attribute. - /// - /// null if the attribute does not exist and the value - /// of the if it does. - public static bool? IsPasswordExpired(ConnectorObject obj) - { - ConnectorAttribute pwd = obj.GetAttributeByName(OperationalAttributes.PASSWORD_EXPIRED_NAME); - return (pwd == null) ? null : GetBooleanValue(pwd); - } - - /// - /// Get the enable date from the set of attributes. - /// - /// set of attribute to find the enable date - /// . - /// - /// null if the attribute does not exist and the value - /// of the if it does. - public static DateTime? GetEnableDate(ICollection attrs) - { - ConnectorAttribute attr = Find(OperationalAttributes.ENABLE_DATE_NAME, attrs); - return (attr == null) ? null : GetDateTimeValue(attr); - } - } - #endregion - - #region ConnectorAttributeInfoUtil - public static class ConnectorAttributeInfoUtil - { - /// - /// Transform a Collection of instances into - /// a . - /// - /// - /// The key to each element in the map is the name of - /// an AttributeInfo. The value of each element in the map is the - /// AttributeInfo instance with that name. - /// - /// set of AttributeInfo to transform to a map. - /// a map of string and AttributeInfo. - /// iff the parameter attributes is - /// null. - public static IDictionary ToMap( - ICollection attributes) - { - IDictionary - ret = new Dictionary( - StringComparer.OrdinalIgnoreCase); - foreach (ConnectorAttributeInfo attr in attributes) - { - ret[attr.Name] = attr; - } - return ret; - } - - /// - /// Find the of the given name in the . - /// - /// - /// 's name to search for. - /// - /// of AttributeInfo to search. - /// - /// with the specified otherwise null. - public static ConnectorAttributeInfo Find(string name, ICollection attrs) - { - Assertions.NullCheck(name, "name"); - ICollection attributes = CollectionUtil.NullAsEmpty(attrs); - foreach (ConnectorAttributeInfo attr in attributes) - { - if (attr.Is(name)) - { - return attr; - } - } - return null; - } - } - #endregion - - #region BigDecimal - /// - /// Placeholder since C# doesn't have a BigInteger - /// - public sealed class BigDecimal - { - private BigInteger _unscaledVal; - private int _scale; - public BigDecimal(BigInteger unscaledVal, - int scale) - { - if (unscaledVal == null) - { - throw new ArgumentNullException(); - } - _unscaledVal = unscaledVal; - _scale = scale; - } - public BigInteger UnscaledValue - { - get - { - return _unscaledVal; - } - } - public int Scale - { - get - { - return _scale; - } - } - public override bool Equals(object o) - { - BigDecimal other = o as BigDecimal; - if (other != null) - { - return UnscaledValue.Equals(other.UnscaledValue) && - Scale == other.Scale; - } - return false; - } - public override int GetHashCode() - { - return _unscaledVal.GetHashCode(); - } - - public override string ToString() - { - return UnscaledValue.ToString(); - } - } - #endregion - - #region BigInteger - /// - /// Placeholder since C# doesn't have a BigInteger - /// - public sealed class BigInteger - { - private string _value; - public BigInteger(string val) - { - if (val == null) - { - throw new ArgumentNullException(); - } - _value = val; - } - public string Value - { - get - { - return _value; - } - } - public override bool Equals(object o) - { - BigInteger other = o as BigInteger; - if (other != null) - { - return Value.Equals(other.Value); - } - return false; - } - public override int GetHashCode() - { - return _value.GetHashCode(); - } - public override string ToString() - { - return _value; - } - } - #endregion - - #region ConnectorAttribute - /// - /// Represents a named collection of values within a resource object, - /// although the simplest case is a name-value pair (e.g., email, - /// employeeID). Values can be empty, null, or set with various types. - /// Empty and null are supported because it makes a difference on some - /// resources (in particular database resources). The developer of a - /// Connector will use an builder to construct an instance of - /// ConnectorAttribute. - /// - public class ConnectorAttribute - { - private readonly string _name; - private readonly IList _value; - - internal ConnectorAttribute(string name, IList val) - { - if (StringUtil.IsBlank(name)) - { - throw new ArgumentException("Name must not be blank!"); - } - if (OperationalAttributes.PASSWORD_NAME.Equals(name) || - OperationalAttributes.CURRENT_PASSWORD_NAME.Equals(name)) - { - // check the value.. - if (val == null || val.Count != 1) - { - String MSG = "Must be a single value."; - throw new ArgumentException(MSG); - } - if (!(val[0] is GuardedString)) - { - const string MSG = "Password value must be an instance of GuardedString."; - throw new ArgumentException(MSG); - } - } - _name = name; - // copy to prevent corruption preserve null - _value = (val == null) ? null : CollectionUtil.NewReadOnlyList(val); - } - - public string Name - { - get - { - return _name; - } - } - - public IList Value - { - get - { - return _value; - } - } - - public bool Is(string name) - { - return NameUtil.NamesEqual(_name, name); - } - - public sealed override bool Equals(Object obj) - { - // test identity - if (this == obj) - { - return true; - } - // test for null.. - if (obj == null) - { - return false; - } - // test that the exact class matches - if (!(GetType().Equals(obj.GetType()))) - { - return false; - } - // test name field.. - ConnectorAttribute other = (ConnectorAttribute)obj; - if (!Is(other._name)) - { - return false; - } - - if (!CollectionUtil.Equals(_value, other._value)) - { - return false; - } - return true; - } - - public sealed override int GetHashCode() - { - return NameUtil.GetNameHashCode(_name); - } - - - public override string ToString() - { - // poor man's consistent toString impl.. - StringBuilder bld = new StringBuilder(); - bld.Append("ConnectorAttribute: "); - IDictionary map = new Dictionary(); - map["Name"] = Name; - map["Value"] = Value; - bld.Append(map.ToString()); - return bld.ToString(); - } - } - #endregion - - #region ConnectorAttributeBuilder - public sealed class ConnectorAttributeBuilder - { - private const String NAME_ERROR = "Name must not be blank!"; - - private string _name; - private IList _value; - - public ConnectorAttributeBuilder() - { - } - public static ConnectorAttribute Build(String name) - { - return new ConnectorAttributeBuilder() { Name = name }.Build(); - } - public static ConnectorAttribute Build(String name, - params Object[] args) - { - ConnectorAttributeBuilder bld = new ConnectorAttributeBuilder(); - bld.Name = name; - bld.AddValue(args); - return bld.Build(); - } - public static ConnectorAttribute Build(String name, - ICollection val) - { - ConnectorAttributeBuilder bld = new ConnectorAttributeBuilder(); - bld.Name = name; - bld.AddValue(val); - return bld.Build(); - } - - public string Name - { - get - { - return _name; - } - set - { - if (StringUtil.IsBlank(value)) - { - throw new ArgumentException(NAME_ERROR); - } - _name = value; - } - } - - public IList Value - { - get - { - return _value == null ? null : CollectionUtil.AsReadOnlyList(_value); - } - } - - public ConnectorAttributeBuilder AddValue(params Object[] args) - { - AddValuesInternal(args); - return this; - } - public ConnectorAttributeBuilder AddValue(ICollection values) - { - AddValuesInternal(values); - return this; - } - - public ConnectorAttribute Build() - { - if (StringUtil.IsBlank(Name)) - { - throw new ArgumentException(NAME_ERROR); - } - if (Uid.NAME.Equals(_name)) - { - return new Uid(GetSingleStringValue()); - } - else if (Org.IdentityConnectors.Framework.Common.Objects.Name.NAME.Equals(_name)) - { - return new Name(GetSingleStringValue()); - } - return new ConnectorAttribute(Name, _value); - } - private void CheckSingleValue() - { - if (_value == null || _value.Count != 1) - { - const String MSG = "Must be a single value."; - throw new ArgumentException(MSG); - } - } - private String GetSingleStringValue() - { - CheckSingleValue(); - if (!(_value[0] is String)) - { - const String MSG = "Must be single string value."; - throw new ArgumentException(MSG); - } - return (String)_value[0]; - } - private void AddValuesInternal(IEnumerable values) - { - if (values != null) - { - // make sure the list is ready to receive values. - if (_value == null) - { - _value = new List(); - } - // add each value checking to make sure its correct - foreach (Object v in values) - { - FrameworkUtil.CheckAttributeValue(v); - _value.Add(v); - } - } - } - - // ======================================================================= - // Operational Attributes - // ======================================================================= - /// - /// Builds an password expiration date . - /// - /// - /// This - /// represents the date/time a password will expire on a - /// resource. - /// - /// UTC time in milliseconds. - /// an built with the pre-defined name for password - /// expiration date. - public static ConnectorAttribute BuildPasswordExpirationDate(DateTime dateTime) - { - return BuildPasswordExpirationDate(DateTimeUtil.GetUtcTimeMillis(dateTime)); - } - - /// - /// Builds an password expiration date . - /// - /// - /// This - /// represents the date/time a password will expire on a - /// resource. - /// - /// UTC time in milliseconds. - /// an built with the pre-defined name for password - /// expiration date. - public static ConnectorAttribute BuildPasswordExpirationDate(long dateTime) - { - return Build(OperationalAttributes.PASSWORD_EXPIRATION_DATE_NAME, - dateTime); - } - - /// - /// Builds the operational attribute password. - /// - /// the string that represents a password. - /// an attribute that represents a password. - public static ConnectorAttribute BuildPassword(GuardedString password) - { - return Build(OperationalAttributes.PASSWORD_NAME, password); - } - - /// - /// Builds the operational attribute current password. - /// - /// - /// The current password - /// indicates this a password change by the account owner and not an - /// administrator. The use case is that an administrator password change may - /// not keep history or validate against policy. - /// - /// the string that represents a password. - /// an attribute that represents a password. - public static ConnectorAttribute BuildCurrentPassword(GuardedString password) - { - return Build(OperationalAttributes.CURRENT_PASSWORD_NAME, password); - } - - public static ConnectorAttribute BuildPassword(SecureString password) - { - return Build(OperationalAttributes.PASSWORD_NAME, new GuardedString(password)); - } - public static ConnectorAttribute BuildCurrentPassword(SecureString password) - { - return Build(OperationalAttributes.CURRENT_PASSWORD_NAME, new GuardedString(password)); - } - /// - /// Builds ant operational attribute that either represents the object is - /// enabled or sets in disabled depending on where its used for instance on - /// it could be used to create a disabled account. - /// - /// - /// In - /// it would show the object is enabled or disabled. - /// - /// true indicates the object is enabled otherwise false. - /// - /// that determines the enable/disable state of an - /// object. - public static ConnectorAttribute BuildEnabled(bool val) - { - return Build(OperationalAttributes.ENABLE_NAME, val); - } - - /// - /// Builds out an operational that determines the enable - /// date for an object. - /// - /// The date and time to enable a particular object, or the date - /// time an object will be enabled. - /// - /// - /// - public static ConnectorAttribute BuildEnableDate(DateTime date) - { - return BuildEnableDate(DateTimeUtil.GetUtcTimeMillis(date)); - } - - /// - /// Builds out an operational that determines the enable - /// date for an object. - /// - /// - /// The time parameter is UTC in milliseconds. - /// - /// The date and time to enable a particular object, or the date - /// time an object will be enabled. - /// - /// - /// - public static ConnectorAttribute BuildEnableDate(long date) - { - return Build(OperationalAttributes.ENABLE_DATE_NAME, date); - } - - /// - /// Builds out an operational that determines the disable - /// date for an object. - /// - /// The date and time to enable a particular object, or the date - /// time an object will be enabled. - /// - /// - /// - public static ConnectorAttribute BuildDisableDate(DateTime date) - { - return BuildDisableDate(DateTimeUtil.GetUtcTimeMillis(date)); - } - - /// - /// Builds out an operational that determines the disable - /// date for an object. - /// - /// - /// The time parameter is UTC in milliseconds. - /// - /// The date and time to enable a particular object, or the date - /// time an object will be enabled. - /// - /// - /// - public static ConnectorAttribute BuildDisableDate(long date) - { - return Build(OperationalAttributes.DISABLE_DATE_NAME, date); - } - - /// - /// Builds the lock attribute that determines if an object is locked out. - /// - /// true if the object is locked otherwise false. - /// - /// that represents the lock state of an object. - public static ConnectorAttribute BuildLockOut(bool lck) - { - return Build(OperationalAttributes.LOCK_OUT_NAME, lck); - } - - /// - /// Builds out an operational that determines if a password - /// is expired or expires a password. - /// - /// from the API true expires and from the SPI its shows its - /// either expired or not. - /// - /// - /// - public static ConnectorAttribute BuildPasswordExpired(bool expired) - { - return Build(OperationalAttributes.PASSWORD_EXPIRED_NAME, expired); - } - - // ======================================================================= - // Pre-defined Attributes - // ======================================================================= - - /// - /// Builds out a pre-defined that determines the last login - /// date for an object. - /// - /// The date and time of the last login. - /// - /// - /// - public static ConnectorAttribute BuildLastLoginDate(DateTime date) - { - return BuildLastLoginDate(DateTimeUtil.GetUtcTimeMillis(date)); - } - - /// - /// Builds out a pre-defined that determines the last login - /// date for an object. - /// - /// - /// The time parameter is UTC in milliseconds. - /// - /// The date and time of the last login. - /// - /// - /// - public static ConnectorAttribute BuildLastLoginDate(long date) - { - return Build(PredefinedAttributes.LAST_LOGIN_DATE_NAME, date); - } - - /// - /// Builds out a pre-defined that determines the last - /// password change date for an object. - /// - /// The date and time the password was changed. - /// - /// - /// - public static ConnectorAttribute BuildLastPasswordChangeDate(DateTime date) - { - return BuildLastPasswordChangeDate(DateTimeUtil.GetUtcTimeMillis(date)); - } - - /// - /// Builds out a pre-defined that determines the last - /// password change date for an object. - /// - /// The date and time the password was changed. - /// - /// - /// - public static ConnectorAttribute BuildLastPasswordChangeDate(long date) - { - return Build(PredefinedAttributes.LAST_PASSWORD_CHANGE_DATE_NAME, date); - } - - /// - /// Common password policy attribute where the password must be changed every - /// so often. - /// - /// - /// The value for this attribute is milliseconds since its the - /// lowest common denominator. - /// - public static ConnectorAttribute BuildPasswordChangeInterval(long val) - { - return Build(PredefinedAttributes.PASSWORD_CHANGE_INTERVAL_NAME, val); - } - } - #endregion - - #region ConnectorMessages - /// - /// Message catalog for a given connector. - /// - public interface ConnectorMessages - { - /// - /// Formats the given message key in the current UI culture. - /// - /// The message key to format. - /// The default message if key is not found. If null, defaults - /// to key. - /// Parameters with which to format the message. - /// The formatted string. - String Format(String key, String dflt, params object[] args); - } - #endregion - - #region ConnectorObject - public sealed class ConnectorObject - { - private readonly ObjectClass _objectClass; - private readonly IDictionary _attrs; - public ConnectorObject(ObjectClass objectClass, ICollection attrs) - { - if (objectClass == null) - { - throw new ArgumentException("ObjectClass may not be null"); - } - if (attrs == null || attrs.Count == 0) - { - throw new ArgumentException("attrs cannot be empty or null."); - } - _objectClass = objectClass; - _attrs = - CollectionUtil.NewReadOnlyDictionary(attrs, - value => { return value.Name; }); - if (!_attrs.ContainsKey(Uid.NAME)) - { - const String MSG = "The ConnectorAttribute set must contain a Uid."; - throw new ArgumentException(MSG); - } - if (!_attrs.ContainsKey(Name.NAME)) - { - const string MSG = "The ConnectorAttribute set must contain a Name."; - throw new ArgumentException(MSG); - } - } - public ICollection GetAttributes() - { - return _attrs.Values; - } - public ConnectorAttribute GetAttributeByName(string name) - { - return CollectionUtil.GetValue(_attrs, name, null); - } - public Uid Uid - { - get - { - return (Uid)GetAttributeByName(Uid.NAME); - } - } - public Name Name - { - get - { - return (Name)GetAttributeByName(Name.NAME); - } - } - public ObjectClass ObjectClass - { - get - { - return _objectClass; - } - } - public override int GetHashCode() - { - return CollectionUtil.GetHashCode(_attrs); - } - public override bool Equals(Object o) - { - ConnectorObject other = o as ConnectorObject; - if (other != null) - { - if (!_objectClass.Equals(other.ObjectClass)) - { - return false; - } - return CollectionUtil.Equals(_attrs, other._attrs); - } - return false; - } - } - #endregion - - #region ConnectorObjectBuilder - public sealed class ConnectorObjectBuilder - { - private IDictionary _attributes; - public ConnectorObjectBuilder() - { - _attributes = new Dictionary(); - // default always add the account object class.. - ObjectClass = ObjectClass.ACCOUNT; - } - - public void SetUid(string uid) - { - AddAttribute(new Uid(uid)); - } - - public void SetUid(Uid uid) - { - AddAttribute(uid); - } - - public void SetName(string name) - { - AddAttribute(new Name(name)); - } - - public void SetName(Name name) - { - AddAttribute(name); - } - - public ObjectClass ObjectClass { get; set; } - - // ======================================================================= - // Clone basically.. - // ======================================================================= - /// - /// Takes all the attribute from a and add/overwrite - /// the current attributes. - /// - public ConnectorObjectBuilder Add(ConnectorObject obj) - { - // simply add all the attributes it will include (Uid, ObjectClass..) - foreach (ConnectorAttribute attr in obj.GetAttributes()) - { - AddAttribute(attr); - } - ObjectClass = obj.ObjectClass; - return this; - } - - public ConnectorObjectBuilder AddAttribute(params ConnectorAttribute[] attrs) - { - ValidateParameter(attrs, "attrs"); - foreach (ConnectorAttribute a in attrs) - { - //DONT use Add - it throws exceptions if already there - _attributes[a.Name] = a; - } - return this; - } - public ConnectorObjectBuilder AddAttributes(ICollection attrs) - { - ValidateParameter(attrs, "attrs"); - foreach (ConnectorAttribute a in attrs) - { - _attributes[a.Name] = a; - } - return this; - } - /// - /// Adds values to the attribute. - /// - public ConnectorObjectBuilder AddAttribute(String name, params object[] objs) - { - AddAttribute(ConnectorAttributeBuilder.Build(name, objs)); - return this; - } - - /// - /// Adds each object in the collection. - /// - public ConnectorObjectBuilder AddAttribute(String name, ICollection obj) - { - AddAttribute(ConnectorAttributeBuilder.Build(name, obj)); - return this; - } - public ConnectorObject Build() - { - // check that there are attributes to return.. - if (_attributes.Count == 0) - { - throw new InvalidOperationException("No attributes set!"); - } - return new ConnectorObject(ObjectClass, _attributes.Values); - } - private static void ValidateParameter(Object param, String paramName) - { - if (param == null) - { - String FORMAT = "Parameter " + param + " must not be null!"; - throw new NullReferenceException(FORMAT); - } - } - } - #endregion - - #region ConnectorAttributeInfo - public sealed class ConnectorAttributeInfo - { - private readonly string _name; - private readonly Type _type; - private readonly Flags _flags; - - /// - /// Enum of modifier flags to use for attributes. - /// - /// - /// Note that - /// this enum is designed for configuration by exception such that - /// an empty set of flags are the defaults: - /// - /// - /// updateable - /// - /// - /// - /// creatable - /// - /// - /// - /// returned by default - /// - /// - /// - /// readable - /// - /// - /// - /// single-valued - /// - /// - /// - /// optional - /// - /// - /// - /// - [FlagsAttribute] - public enum Flags - { - NONE = 0, - REQUIRED = 1, - MULTIVALUED = 2, - NOT_CREATABLE = 4, - NOT_UPDATEABLE = 8, - NOT_READABLE = 16, - NOT_RETURNED_BY_DEFAULT = 32 - } - - internal ConnectorAttributeInfo(string name, Type type, - Flags flags) - { - if (StringUtil.IsBlank(name)) - { - throw new ArgumentException("Name must not be blank!"); - } - if ((OperationalAttributes.PASSWORD_NAME.Equals(name) || - OperationalAttributes.CURRENT_PASSWORD_NAME.Equals(name)) && - !typeof(GuardedString).Equals(type)) - { - String MSG = "Password based attributes must be of type GuardedString."; - throw new ArgumentException(MSG); - } - // check the type.. - FrameworkUtil.CheckAttributeType(type); - _name = name; - _type = type; - _flags = flags; - if (!IsReadable && IsReturnedByDefault) - { - throw new ArgumentException("Attribute " + name + " is flagged as not-readable, so it should also be as not-returned-by-default."); - } - } - - - /// - /// The native name of the attribute. - /// - /// the native name of the attribute its describing. - public string Name - { - get - { - return _name; - } - } - - /// - /// The basic type associated with this attribute. - /// - /// - /// All primitives are - /// supported. - /// - /// the native type if uses. - public Type ValueType - { - get - { - return _type; - } - } - - /// - /// Returns the set of flags associated with the attribute. - /// - /// the set of flags associated with the attribute - public Flags InfoFlags - { - get - { - return _flags; - } - } - - - public bool Is(string name) - { - return NameUtil.NamesEqual(_name, name); - } - - /// - /// Determines if the attribute is readable. - /// - /// true if the attribute is readable else false. - public bool IsReadable - { - get - { - return (_flags & Flags.NOT_READABLE) == 0; - } - } - - /// - /// Determines if the attribute is writable on create. - /// - /// true if the attribute is writable on create else false. - public bool IsCreatable - { - get - { - return (_flags & Flags.NOT_CREATABLE) == 0; - } - } - - /// - /// Determines if the attribute is writable on update. - /// - /// true if the attribute is writable on update else false. - public bool IsUpdateable - { - get - { - return (_flags & Flags.NOT_UPDATEABLE) == 0; - } - } - - /// - /// Determines whether this attribute is required for creates. - /// - /// true if the attribute is required for an object else false. - public bool IsRequired - { - get - { - return (_flags & Flags.REQUIRED) != 0; - } - } - - /// - /// Determines if this attribute can handle multiple values. - /// - /// - /// There is a - /// special case with byte[] since in most instances this denotes a single - /// object. - /// - /// true if the attribute is multi-value otherwise false. - public bool IsMultiValued - { - get - { - return (_flags & Flags.MULTIVALUED) != 0; - } - } - - /// - /// Determines if the attribute is returned by default. - /// - /// - /// Indicates if an - /// will be returned during or - /// inside a by default. The default - /// value is true. - /// - /// false iff the attribute should not be returned by default. - public bool IsReturnedByDefault - { - get - { - return (_flags & Flags.NOT_RETURNED_BY_DEFAULT) == 0; - } - } - - public override bool Equals(Object o) - { - ConnectorAttributeInfo other = o as ConnectorAttributeInfo; - if (other != null) - { - if (!Is(other.Name)) - { - return false; - } - if (!ValueType.Equals(other.ValueType)) - { - return false; - } - if (_flags != other._flags) - { - return false; - } - return true; - } - return false; - } - - public override int GetHashCode() - { - return NameUtil.GetNameHashCode(_name); - } - - public override string ToString() - { - return SerializerUtil.SerializeXmlObject(this, false); - } - } - #endregion - - #region ConnectorAttributeInfoBuilder - /// - /// Simplifies the process of building 'AttributeInfo' objects. - /// - /// - /// This class is - /// responsible for providing a default implementation of . - /// - /// AttributeInfoBuilder bld = new AttributeInfoBuilder("email"); - /// bld.setRequired(true); - /// AttributeInfo info = bld.build(); - /// - /// - /// Will Droste - /// $Revision: 1.9 $ - /// 1.0 - public sealed class ConnectorAttributeInfoBuilder - { - - private String _name; - private Type _type; - private ConnectorAttributeInfo.Flags _flags; - - /// - /// Creates an builder with all the defaults set. - /// - /// - /// The name must be set before - /// the 'build' method is called otherwise an - /// is thrown. - ///
-        /// Name: <not set>
-        /// Readable: true
-        /// Writeable: true
-        /// Required: false
-        /// Type: string
-        /// MultiValue: false
-        /// 
- ///
- public ConnectorAttributeInfoBuilder() - { - ValueType = (typeof(String)); - _flags = ConnectorAttributeInfo.Flags.NONE; - } - - /// - /// Creates an builder with all the defaults set. - /// - /// - /// The name must be set before - /// the 'build' method is called otherwise an - /// is thrown. - ///
-        /// Name: <not set>
-        /// Readable: true
-        /// Writeable: true
-        /// Required: false
-        /// Type: string
-        /// MultiValue: false
-        /// 
- ///
- public ConnectorAttributeInfoBuilder(String name) - : this(name, typeof(String)) - { - } - - /// - /// Creates an builder with all the defaults set. - /// - /// - /// The name must be set before - /// the 'build' method is called otherwise an - /// is thrown. - ///
-        /// Name: <not set>
-        /// Readable: true
-        /// Writeable: true
-        /// Required: false
-        /// Type: string
-        /// MultiValue: false
-        /// 
- ///
- public ConnectorAttributeInfoBuilder(String name, Type type) - { - Name = (name); - ValueType = (type); - //noneOf means the defaults - _flags = ConnectorAttributeInfo.Flags.NONE; - } - - /// - /// Builds an object based on the properties set. - /// - /// - /// based on the properties set. - public ConnectorAttributeInfo Build() - { - return new ConnectorAttributeInfo(_name, _type, _flags); - } - - /// - /// Sets the unique name of the object. - /// - /// unique name of the object. - public String Name - { - set - { - if (StringUtil.IsBlank(value)) - { - throw new ArgumentException("Argument must not be blank."); - } - _name = value; - } - } - - /// - /// Please see for the - /// definitive list of supported types. - /// - /// type for an 's value. - /// if the Class is not a supported type. - public Type ValueType - { - set - { - FrameworkUtil.CheckAttributeType(value); - _type = value; - } - } - - /// - /// Determines if the attribute is readable. - /// - public bool Readable - { - set - { - SetFlag(ConnectorAttributeInfo.Flags.NOT_READABLE, !value); - } - } - - /// - /// Determines if the attribute is writable. - /// - public bool Creatable - { - set - { - SetFlag(ConnectorAttributeInfo.Flags.NOT_CREATABLE, !value); - } - } - - /// - /// Determines if this attribute is required. - /// - public bool Required - { - set - { - SetFlag(ConnectorAttributeInfo.Flags.REQUIRED, value); - } - } - - /// - /// Determines if this attribute supports multivalue. - /// - public bool MultiValued - { - set - { - SetFlag(ConnectorAttributeInfo.Flags.MULTIVALUED, value); - } - } - - /// - /// Determines if this attribute writable during update. - /// - public bool Updateable - { - set - { - SetFlag(ConnectorAttributeInfo.Flags.NOT_UPDATEABLE, !value); - } - } - - public bool ReturnedByDefault - { - set - { - SetFlag(ConnectorAttributeInfo.Flags.NOT_RETURNED_BY_DEFAULT, !value); - } - } - - /// - /// Sets all of the flags for this builder. - /// - /// The set of attribute info flags. Null means clear all flags. - /// - /// NOTE: EnumSet.noneOf(AttributeInfo.Flags.class) results in - /// an attribute with the default behavior: - /// - /// - /// updateable - /// - /// - /// - /// creatable - /// - /// - /// - /// returned by default - /// - /// - /// - /// readable - /// - /// - /// - /// single-valued - /// - /// - /// - /// optional - /// - /// - /// - /// - /// - public ConnectorAttributeInfo.Flags InfoFlags - { - set - { - _flags = value; - } - } - - private void SetFlag(ConnectorAttributeInfo.Flags flag, bool value) - { - if (value) - { - _flags = _flags | flag; - } - else - { - _flags = _flags & ~flag; - } - } - - /// - /// Convenience method to create an AttributeInfo. - /// - /// - /// Equivalent to - /// - /// new AttributeInfoBuilder(name,type).setFlags(flags).build() - /// - /// - /// The name of the attribute - /// The type of the attribute - /// The flags for the attribute. Null means clear all flags - /// The attribute info - public static ConnectorAttributeInfo Build(String name, Type type, - ConnectorAttributeInfo.Flags flags) - { - return new ConnectorAttributeInfoBuilder(name, type) { InfoFlags = flags }.Build(); - } - /// - /// Convenience method to create an AttributeInfo. - /// - /// - /// Equivalent to - /// - /// AttributeInfoBuilder.build(name,type,null) - /// - /// - /// The name of the attribute - /// The type of the attribute - /// The flags for the attribute - /// The attribute info - public static ConnectorAttributeInfo Build(String name, Type type) - { - return Build(name, type, ConnectorAttributeInfo.Flags.NONE); - } - - /// - /// Convenience method to create an AttributeInfo. - /// - /// - /// Equivalent to - /// - /// AttributeInfoBuilder.build(name,type) - /// - /// - /// The name of the attribute - /// The attribute info - public static ConnectorAttributeInfo Build(String name) - { - return Build(name, typeof(String)); - } - } - #endregion - - #region FileName - /// - /// Placeholder for java.io.File since C#'s - /// FileInfo class throws exceptions if the - /// file doesn't exist. - /// - public sealed class FileName - { - private string _path; - public FileName(string path) - { - if (path == null) - { - throw new ArgumentNullException(); - } - _path = path; - } - public string Path - { - get - { - return _path; - } - } - public override bool Equals(object o) - { - FileName other = o as FileName; - if (other != null) - { - return Path.Equals(other.Path); - } - return false; - } - public override int GetHashCode() - { - return _path.GetHashCode(); - } - public override string ToString() - { - return _path; - } - } - #endregion - - #region Name - public sealed class Name : ConnectorAttribute - { - public readonly static string NAME = ConnectorAttributeUtil.CreateSpecialName("NAME"); - public readonly static ConnectorAttributeInfo INFO = - new ConnectorAttributeInfoBuilder(NAME) { Required = true }.Build(); - - public Name(String value) - : base(NAME, CollectionUtil.NewReadOnlyList(value)) - { - } - - /// - /// The single value of the attribute that is the unique id of an object. - /// - /// value that identifies an object. - public String GetNameValue() - { - return ConnectorAttributeUtil.GetStringValue(this); - } - } - #endregion - - #region ObjectClassUtil - public static class ObjectClassUtil - { - /// - /// Determines if this object class is a special object class. - /// Special object classes include the predefined ones, such as - /// and . - /// - /// the object class to test - /// true iff the object class is special - /// if the object class parameter is null - public static bool IsSpecial(ObjectClass oclass) - { - String name = oclass.GetObjectClassValue(); - return IsSpecialName(name); - } - - /// - /// Determines whether the specified object class name is special in the - /// sense of . - /// - /// the name of the object class to test - /// true iff the object class name is special - public static bool IsSpecialName(String name) - { - return NameUtil.IsSpecialName(name); - } - - /// - /// Create a special name from the specified name. Add the __ - /// string as both prefix and suffix. This indicates that a name - /// identifies a special object class such as a predefined one. - /// - /// object class name to make special - /// name constructed for use as a special name - public static string CreateSpecialName(string name) - { - return NameUtil.CreateSpecialName(name); - } - - /// - /// Compares two object class names for equality. - /// - /// the first object class name - /// the second object class name - /// true iff the two object class names are equal - public static bool NamesEqual(string name1, string name2) - { - return NameUtil.NamesEqual(name2, name2); - } - } - #endregion - - #region ObjectClass - public sealed class ObjectClass - { - public static readonly String ACCOUNT_NAME = ObjectClassUtil.CreateSpecialName("ACCOUNT"); - public static readonly String GROUP_NAME = ObjectClassUtil.CreateSpecialName("GROUP"); - /// - /// Denotes an account based object. - /// - public static readonly ObjectClass ACCOUNT = new ObjectClass(ACCOUNT_NAME); - /// - /// Denotes a group based object. - /// - public static readonly ObjectClass GROUP = new ObjectClass(GROUP_NAME); - - private readonly String _type; - - public ObjectClass(String type) - { - if (type == null) - { - throw new ArgumentException("Type cannot be null."); - } - _type = type; - } - public String GetObjectClassValue() - { - return _type; - } - - /// - /// Convenience method to build the display name key for - /// an object class. - /// - /// The display name key. - public String GetDisplayNameKey() - { - return "MESSAGE_OBJECT_CLASS_" + _type.ToUpper(CultureInfo.GetCultureInfo("en-US")); - } - - /// - /// Determines if the 'name' matches this . - /// - /// case-insensitive string representation of the ObjectClass's - /// type. - /// - /// true if the case-insensitive name is equal to - /// that of the one in this . - public bool Is(String name) - { - return NameUtil.NamesEqual(_type, name); - } - - public override int GetHashCode() - { - return NameUtil.GetNameHashCode(_type); - } - - public override bool Equals(object obj) - { - // test identity - if (this == obj) - { - return true; - } - - // test for null.. - if (obj == null) - { - return false; - } - - // test that the exact class matches - if (!(GetType().Equals(obj.GetType()))) - { - return false; - } - - ObjectClass other = (ObjectClass)obj; - - if (!Is(other._type)) - { - return false; - } - - return true; - } - - public override string ToString() - { - return "ObjectClass: " + _type; - } - } - #endregion - - #region ObjectClassInfo - public sealed class ObjectClassInfo - { - private readonly String _type; - private readonly ICollection _info; - private readonly bool _isContainer; - - public ObjectClassInfo(String type, - ICollection attrInfo, - bool isContainer) - { - Assertions.NullCheck(type, "type"); - _type = type; - _info = CollectionUtil.NewReadOnlySet(attrInfo); - _isContainer = isContainer; - // check to make sure name exists - IDictionary dict - = ConnectorAttributeInfoUtil.ToMap(attrInfo); - if (!dict.ContainsKey(Name.NAME)) - { - const string MSG = "Missing 'Name' connector attribute info."; - throw new ArgumentException(MSG); - } - } - - public ICollection ConnectorAttributeInfos - { - get - { - return this._info; - } - } - - public String ObjectType - { - get - { - return this._type; - } - } - - /// - /// Determines if the 'name' matches this . - /// - /// case-insensitive string representation of the ObjectClassInfo's - /// type. - /// - /// true if the case insensitive type is equal to - /// that of the one in this . - public bool Is(String name) - { - return NameUtil.NamesEqual(_type, name); - } - - public bool IsContainer - { - get - { - return this._isContainer; - } - } - - public override int GetHashCode() - { - return NameUtil.GetNameHashCode(_type); - } - - public override bool Equals(Object obj) - { - // test identity - if (this == obj) - { - return true; - } - - // test for null.. - if (obj == null) - { - return false; - } - - if (!obj.GetType().Equals(this.GetType())) - { - return false; - } - - ObjectClassInfo other = obj as ObjectClassInfo; - - if (!Is(other.ObjectType)) - { - return false; - } - - if (!CollectionUtil.Equals(ConnectorAttributeInfos, - other.ConnectorAttributeInfos)) - { - return false; - } - - if (_isContainer != other._isContainer) - { - return false; - } - - return true; - } - - public override string ToString() - { - return SerializerUtil.SerializeXmlObject(this, false); - } - } - #endregion - - #region ObjectClassInfoBuilder - /// - /// Used to help facilitate the building of objects. - /// - public sealed class ObjectClassInfoBuilder - { - private bool _isContainer; - private IDictionary _info; - - public ObjectClassInfoBuilder() - { - _info = new Dictionary(); - ObjectType = ObjectClass.ACCOUNT_NAME; - } - - public string ObjectType { get; set; } - - /// - /// Add each object to the . - /// - public ObjectClassInfoBuilder AddAttributeInfo(ConnectorAttributeInfo info) - { - if (_info.ContainsKey(info.Name)) - { - const string MSG = "ConnectorAttributeInfo of name ''{0}'' already exists!"; - throw new ArgumentException(String.Format(MSG, info.Name)); - } - _info[info.Name] = info; - return this; - } - - public ObjectClassInfoBuilder AddAllAttributeInfo(ICollection info) - { - foreach (ConnectorAttributeInfo cainfo in info) - { - AddAttributeInfo(cainfo); - } - return this; - } - - public bool IsContainer - { - get - { - return _isContainer; - } - set - { - _isContainer = value; - } - } - - public ObjectClassInfo Build() - { - // determine if name is missing and add it by default - if (!_info.ContainsKey(Name.NAME)) - { - _info[Name.NAME] = Name.INFO; - } - return new ObjectClassInfo(ObjectType, _info.Values, _isContainer); - } - } - #endregion - - #region OperationalAttributeInfos - /// - /// for each operational attribute. - /// - public static class OperationalAttributeInfos - { - /// - /// Gets/sets the enable status of an object. - /// - public static readonly ConnectorAttributeInfo ENABLE = - ConnectorAttributeInfoBuilder.Build( - OperationalAttributes.ENABLE_NAME, typeof(bool)); - - /// - /// Gets/sets the enable date for an object. - /// - public static readonly ConnectorAttributeInfo ENABLE_DATE = - ConnectorAttributeInfoBuilder.Build( - OperationalAttributes.ENABLE_DATE_NAME, typeof(long)); - - /// - /// Gets/sets the disable date for an object. - /// - public static readonly ConnectorAttributeInfo DISABLE_DATE = - ConnectorAttributeInfoBuilder.Build( - OperationalAttributes.DISABLE_DATE_NAME, typeof(long)); - - /// - /// Gets/sets the lock out attribute for an object. - /// - public static readonly ConnectorAttributeInfo LOCK_OUT = - ConnectorAttributeInfoBuilder.Build( - OperationalAttributes.LOCK_OUT_NAME, typeof(bool)); - - /// - /// Gets/sets the password expiration date for an object. - /// - public static readonly ConnectorAttributeInfo PASSWORD_EXPIRATION_DATE = - ConnectorAttributeInfoBuilder.Build( - OperationalAttributes.PASSWORD_EXPIRATION_DATE_NAME, typeof(long)); - - /// - /// Normally this is a write-only attribute. - /// - /// - /// Sets the password for an object. - /// - public static readonly ConnectorAttributeInfo PASSWORD = - ConnectorAttributeInfoBuilder.Build( - OperationalAttributes.PASSWORD_NAME, typeof(GuardedString), - ConnectorAttributeInfo.Flags.NOT_READABLE | - ConnectorAttributeInfo.Flags.NOT_RETURNED_BY_DEFAULT); - - /// - /// Used in conjunction with password to do an account level password change. - /// - /// - /// This is for a non-administrator change of the password and therefore - /// requires the current password. - /// - public static readonly ConnectorAttributeInfo CURRENT_PASSWORD = - ConnectorAttributeInfoBuilder.Build( - OperationalAttributes.CURRENT_PASSWORD_NAME, typeof(GuardedString), - ConnectorAttributeInfo.Flags.NOT_READABLE | - ConnectorAttributeInfo.Flags.NOT_RETURNED_BY_DEFAULT); - - /// - /// Used to determine if a password is expired or to expire a password. - /// - public static readonly ConnectorAttributeInfo PASSWORD_EXPIRED = - ConnectorAttributeInfoBuilder.Build( - OperationalAttributes.PASSWORD_EXPIRED_NAME, typeof(bool)); - - } - #endregion - - #region OperationalAttributes - /// - /// Operational attributes have special meaning and cannot be represented by pure - /// operations. - /// - /// - /// For instance some administrators would like to create an account - /// in the disabled state. The do not want this to be a two operation process - /// since this can leave the door open to abuse. Therefore special attributes - /// that can perform operations were introduced. The - /// attribute could be added to the set of - /// attribute sent to a Connector for the operation. To tell the - /// to create the account with it in the disabled state whether - /// the target resource itself has an attribute or an additional method must be - /// called. - /// - public static class OperationalAttributes - { - /// - /// Gets/sets the enable status of an object. - /// - public static readonly string ENABLE_NAME = ConnectorAttributeUtil.CreateSpecialName("ENABLE"); - /// - /// Gets/sets the enable date for an object. - /// - public static readonly string ENABLE_DATE_NAME = ConnectorAttributeUtil.CreateSpecialName("ENABLE_DATE"); - /// - /// Gets/sets the disable date for an object. - /// - public static readonly string DISABLE_DATE_NAME = ConnectorAttributeUtil.CreateSpecialName("DISABLE_DATE"); - /// - /// Gets/sets the lock out attribute for an object. - /// - public static readonly string LOCK_OUT_NAME = ConnectorAttributeUtil.CreateSpecialName("LOCK_OUT"); - /// - /// Gets/sets the password expiration date for an object. - /// - public static readonly string PASSWORD_EXPIRATION_DATE_NAME = ConnectorAttributeUtil.CreateSpecialName("PASSWORD_EXPIRATION_DATE"); - /// - /// Gets/sets the password expired for an object. - /// - public static readonly string PASSWORD_EXPIRED_NAME = ConnectorAttributeUtil.CreateSpecialName("PASSWORD_EXPIRED"); - /// - /// Normally this is a write-only attribute. - /// - /// - /// Sets the password for an object. - /// - public static readonly string PASSWORD_NAME = ConnectorAttributeUtil.CreateSpecialName("PASSWORD"); - /// - /// Used in conjunction with password to do an account level password change. - /// - /// - /// This is for a non-administrator change of the password and therefore - /// requires the current password. - /// - public static readonly string CURRENT_PASSWORD_NAME = ConnectorAttributeUtil.CreateSpecialName("CURRENT_PASSWORD"); - - // ======================================================================= - // Helper Methods.. - // ======================================================================= - public static readonly ICollection OPERATIONAL_ATTRIBUTE_NAMES = - CollectionUtil.NewReadOnlySet( - LOCK_OUT_NAME, - ENABLE_NAME, - ENABLE_DATE_NAME, - DISABLE_DATE_NAME, - PASSWORD_EXPIRATION_DATE_NAME, - PASSWORD_NAME, - CURRENT_PASSWORD_NAME, - PASSWORD_EXPIRED_NAME - ); - - public static ICollection GetOperationalAttributeNames() - { - return CollectionUtil.NewReadOnlySet(OPERATIONAL_ATTRIBUTE_NAMES); - } - public static bool IsOperationalAttribute(ConnectorAttribute attr) - { - string name = (attr != null) ? attr.Name : null; - return OPERATIONAL_ATTRIBUTE_NAMES.Contains(name); - } - } - #endregion - - #region PredefinedAttributes - /// - /// List of well known or pre-defined attributes. - /// - /// - /// Common attributes that most - /// resources have that are not operational in nature. - /// - public static class PredefinedAttributes - { - /// - /// Attribute that should hold a reasonable value to - /// display for the value of an object. - /// - /// - /// If this is not present, then the - /// application will have to use the NAME to show the value. - /// - public static readonly String SHORT_NAME = ConnectorAttributeUtil.CreateSpecialName("SHORT_NAME"); - - /// - /// Attribute that should hold the value of the object's description, - /// if one is available. - /// - public static readonly String DESCRIPTION = ConnectorAttributeUtil.CreateSpecialName("DESCRIPTION"); - - /// - /// Read-only attribute that shows the last date/time the password was - /// changed. - /// - public static readonly string LAST_PASSWORD_CHANGE_DATE_NAME = ConnectorAttributeUtil.CreateSpecialName("LAST_PASSWORD_CHANGE_DATE"); - - /// - /// Common password policy attribute where the password must be changed every - /// so often. - /// - /// - /// The value for this attribute is milliseconds since its the - /// lowest common denominator. - /// - public static readonly string PASSWORD_CHANGE_INTERVAL_NAME = ConnectorAttributeUtil.CreateSpecialName("PASSWORD_CHANGE_INTERVAL"); - - /// - /// Last login date for an account. - /// - /// - /// This is usually used to determine inactivity. - /// - public static readonly string LAST_LOGIN_DATE_NAME = ConnectorAttributeUtil.CreateSpecialName("LAST_LOGIN_DATE"); - - /// - /// Groups an account object belongs to. - /// - public static readonly string GROUPS_NAME = ConnectorAttributeUtil.CreateSpecialName("GROUPS"); - } - #endregion - - #region PredefinedAttributeInfos - public static class PredefinedAttributeInfos - { - /// - /// Attribute that should hold a reasonable value to - /// display for the value of an object. - /// - /// - /// If this is not present, then the - /// application will have to use the NAME to show the value. - /// - public static readonly ConnectorAttributeInfo SHORT_NAME = - ConnectorAttributeInfoBuilder.Build(PredefinedAttributes.SHORT_NAME); - - /// - /// Attribute that should hold the value of the object's description, - /// if one is available. - /// - public static readonly ConnectorAttributeInfo DESCRIPTION = - ConnectorAttributeInfoBuilder.Build(PredefinedAttributes.DESCRIPTION); - /// - /// Read-only attribute that shows the last date/time the password was - /// changed. - /// - public static readonly ConnectorAttributeInfo LAST_PASSWORD_CHANGE_DATE = - ConnectorAttributeInfoBuilder.Build( - PredefinedAttributes.LAST_PASSWORD_CHANGE_DATE_NAME, - typeof(long), - ConnectorAttributeInfo.Flags.NOT_CREATABLE | - ConnectorAttributeInfo.Flags.NOT_UPDATEABLE); - - /// - /// Common password policy attribute where the password must be changed every - /// so often. - /// - /// - /// The value for this attribute is milliseconds since its the - /// lowest common denominator. - /// - public static readonly ConnectorAttributeInfo PASSWORD_CHANGE_INTERVAL = - ConnectorAttributeInfoBuilder.Build( - PredefinedAttributes.PASSWORD_CHANGE_INTERVAL_NAME, typeof(long)); - - /// - /// Last login date for an account. - /// - /// - /// This is usually used to determine - /// inactivity. - /// - public static readonly ConnectorAttributeInfo LAST_LOGIN_DATE = - ConnectorAttributeInfoBuilder.Build( - PredefinedAttributes.LAST_LOGIN_DATE_NAME, - typeof(long), - ConnectorAttributeInfo.Flags.NOT_CREATABLE | - ConnectorAttributeInfo.Flags.NOT_UPDATEABLE); - - /// - /// Groups that an account or person belong to. - /// - /// - /// The Attribute values are the - /// UID value of each group that an account has membership in. - /// - public static readonly ConnectorAttributeInfo GROUPS = - ConnectorAttributeInfoBuilder.Build(PredefinedAttributes.GROUPS_NAME, - typeof(String), - ConnectorAttributeInfo.Flags.MULTIVALUED | - ConnectorAttributeInfo.Flags.NOT_RETURNED_BY_DEFAULT); - } - #endregion - - #region OperationOptions - /// - /// Arbitrary options to be passed into various operations. - /// - /// - /// This serves - /// as a catch-all for extra options. - /// - public sealed class OperationOptions - { - /// - /// An option to use with that specified the scope - /// under which to perform the search. - /// - /// - /// To be used in conjunction with - /// . Must be one of the following values - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public const String OP_SCOPE = "SCOPE"; - public const String SCOPE_OBJECT = "object"; - public const String SCOPE_ONE_LEVEL = "onelevel"; - public const String SCOPE_SUBTREE = "subtree"; - - /// - /// An option to use with that specified the container - /// under which to perform the search. - /// - /// - /// Must be of type . - /// Should be implemented for those object classes whose - /// returns true. - /// - public const String OP_CONTAINER = "CONTAINER"; - - /// - /// An option to use with and possibly others - /// that specifies an account under which to execute the script/operation. - /// - /// - /// The specified account will appear to have performed any action that the - /// script/operation performs. - /// - /// Check the javadoc for a particular connector to see whether that - /// connector supports this option. - /// - /// - public static readonly string OP_RUN_AS_USER = "RUN_AS_USER"; - - /// - /// An option to use with and possibly others - /// that specifies a password under which to execute the script/operation. - /// - public static readonly string OP_RUN_WITH_PASSWORD = "RUN_WITH_PASSWORD"; - - /// - /// Determines the attributes to retrieve during and - /// . - /// - public static readonly string OP_ATTRIBUTES_TO_GET = "ATTRS_TO_GET"; - - private readonly IDictionary _operationOptions; - - /// - /// Public only for serialization; please use . - /// - /// The options. - public OperationOptions(IDictionary operationOptions) - { - foreach (Object val in operationOptions.Values) - { - FrameworkUtil.CheckOperationOptionValue(val); - } - //clone options to do a deep copy in case anything - //is an array - IDictionary operationOptionsClone = (IDictionary)SerializerUtil.CloneObject(operationOptions); - _operationOptions = CollectionUtil.NewReadOnlyDictionary(operationOptionsClone); - } - - /// - /// Returns a map of options. - /// - /// - /// Each value in the map - /// must be of a type that the framework can serialize. - /// See for a list of supported types. - /// - /// A map of options. - public IDictionary Options - { - get - { - return _operationOptions; - } - } - - /// - /// Convenience method that returns . - /// - /// The value for . - public String Scope - { - get - { - return (String)CollectionUtil.GetValue(_operationOptions, OP_SCOPE, null); - } - } - - /// - /// Convenience method that returns . - /// - /// The value for . - public QualifiedUid getContainer - { - get - { - return (QualifiedUid)CollectionUtil.GetValue(_operationOptions, OP_CONTAINER, null); - } - } - - /// - /// Get the string array of attribute names to return in the object. - /// - public string[] AttributesToGet - { - get - { - return (string[])CollectionUtil.GetValue( - _operationOptions, OP_ATTRIBUTES_TO_GET, null); - } - } - - /// - /// Get the account to run the operation as.. - /// - public string RunAsUser - { - get - { - return (string)CollectionUtil.GetValue( - _operationOptions, OP_RUN_AS_USER, null); - } - } - - /// - /// Get the password to run the operation as.. - /// - public GuardedString RunWithPassword - { - get - { - return (GuardedString)CollectionUtil.GetValue( - _operationOptions, OP_RUN_WITH_PASSWORD, null); - } - } - - public override string ToString() - { - StringBuilder bld = new StringBuilder(); - bld.Append("OperationOptions: ").Append(Options); - return bld.ToString(); - } - } - #endregion - - #region OperationOptionsBuilder - /// - /// Builder for . - /// - public sealed class OperationOptionsBuilder - { - private readonly IDictionary _options; - - /// - /// Create a builder with an empty set of options. - /// - public OperationOptionsBuilder() - { - _options = new Dictionary(); - } - - /// - /// Create a builder from an existing set of options. - /// - /// The existing set of options. Must not be null. - public OperationOptionsBuilder(OperationOptions options) - { - Assertions.NullCheck(options, "options"); - // clone options to do a deep copy in case anything - // is an array - IDictionary operationOptionsClone = (IDictionary)SerializerUtil - .CloneObject(options.Options); - _options = CollectionUtil.NewDictionary(operationOptionsClone); - } - - /// - /// Sets a given option and a value for that option. - /// - /// The name of the option - /// The value of the option. Must be one of the types that - /// we can serialize. - /// See for a list of supported types. - public void SetOption(String name, Object value) - { - if (name == null) - { - throw new ArgumentException("Argument 'value' cannot be null."); - } - //don't validate value here - we do that implicitly when - //we clone in the constructor of OperationOptions - _options[name] = value; - } - - /// - /// Returns a mutable reference of the options map. - /// - /// A mutable reference of the options map. - public IDictionary Options - { - get - { - //might as well be mutable since it's the builder and - //we don't want to deep copy anyway - return _options; - } - } - - /// - /// Creates the OperationOptions. - /// - /// The newly-created OperationOptions - public OperationOptions Build() - { - return new OperationOptions(_options); - } - - /// - /// Sets the option. - /// - /// list of names. - public string[] AttributesToGet - { - set - { - Assertions.NullCheck(value, "AttributesToGet"); - // don't validate value here - we do that in - // the constructor of OperationOptions - that's - // really the only place we can truly enforce this - _options[OperationOptions.OP_ATTRIBUTES_TO_GET] = value; - } - } - - /// - /// Set the run with password option. - /// - public GuardedString RunWithPassword - { - set - { - Assertions.NullCheck(value, "RunWithPassword"); - _options[OperationOptions.OP_RUN_WITH_PASSWORD] = value; - } - } - - /// - /// Set the run as user option. - /// - public string RunAsUser - { - set - { - Assertions.NullCheck(value, "RunAsUser"); - _options[OperationOptions.OP_RUN_AS_USER] = value; - } - } - /// - /// Convenience method to set - /// - /// The scope. May not be null. - /// A this reference to allow chaining - public string Scope - { - set - { - Assertions.NullCheck(value, "scope"); - _options[OperationOptions.OP_SCOPE] = value; - } - } - - /// - /// Convenience method to set - /// - /// The container. May not be null. - /// A this reference to allow chaining - public QualifiedUid Container - { - set - { - Assertions.NullCheck(value, "container"); - _options[OperationOptions.OP_CONTAINER] = value; - } - } - - } - #endregion - - #region OperationOptionInfo - public sealed class OperationOptionInfo - { - private String _name; - private Type _type; - - public OperationOptionInfo(String name, - Type type) - { - Assertions.NullCheck(name, "name"); - Assertions.NullCheck(type, "type"); - FrameworkUtil.CheckOperationOptionType(type); - _name = name; - _type = type; - } - - public String Name - { - get - { - return _name; - } - } - - public Type OptionType - { - get - { - return _type; - } - } - - public override bool Equals(Object o) - { - if (o is OperationOptionInfo) - { - OperationOptionInfo other = - (OperationOptionInfo)o; - if (!_name.Equals(other._name)) - { - return false; - } - if (!_type.Equals(other._type)) - { - return false; - } - return true; - } - return false; - } - - public override int GetHashCode() - { - return _name.GetHashCode(); - } - - public override string ToString() - { - StringBuilder bld = new StringBuilder(); - bld.Append("OperationOptionInfo("); - bld.Append(_name); - bld.Append(_type.ToString()); - bld.Append(')'); - return bld.ToString(); - } - - } - #endregion - - #region OperationOptionInfoBuilder - public sealed class OperationOptionInfoBuilder - { - private String _name; - private Type _type; - - public OperationOptionInfoBuilder() - { - } - - public OperationOptionInfoBuilder(String name, - Type type) - { - _name = name; - _type = type; - } - - public String Name - { - get - { - return _name; - } - set - { - _name = value; - } - } - - public Type OptionType - { - get - { - return _type; - } - set - { - _type = value; - } - } - - public OperationOptionInfo Build() - { - return new OperationOptionInfo(_name, _type); - } - - public static OperationOptionInfo Build(String name, Type type) - { - return new OperationOptionInfoBuilder(name, type).Build(); - } - - public static OperationOptionInfo Build(String name) - { - return Build(name, typeof(string)); - } - - public static OperationOptionInfo BuildAttributesToGet() - { - return Build(OperationOptions.OP_ATTRIBUTES_TO_GET, typeof(string[])); - } - - public static OperationOptionInfo BuildRunWithPassword() - { - return Build(OperationOptions.OP_RUN_WITH_PASSWORD); - } - - public static OperationOptionInfo BuildRunAsUser() - { - return Build(OperationOptions.OP_RUN_AS_USER); - } - public static OperationOptionInfo BuildScope() - { - return Build(OperationOptions.OP_SCOPE); - } - - public static OperationOptionInfo BuildContainer() - { - return Build(OperationOptions.OP_CONTAINER, typeof(QualifiedUid)); - } - } - #endregion - - #region QualifiedUid - /// - /// A fully-qualified uid. - /// - /// - /// That is, a pair of and - /// . - /// - public sealed class QualifiedUid - { - private readonly ObjectClass _objectClass; - private readonly Uid _uid; - - /// - /// Create a QualifiedUid. - /// - /// The object class. May not be null. - /// The uid. May not be null. - public QualifiedUid(ObjectClass objectClass, - Uid uid) - { - Assertions.NullCheck(objectClass, "objectClass"); - Assertions.NullCheck(uid, "uid"); - _objectClass = objectClass; - _uid = uid; - } - - /// - /// Returns the object class. - /// - /// The object class. - public ObjectClass ObjectClass - { - get - { - return _objectClass; - } - } - - /// - /// Returns the uid. - /// - /// The uid. - public Uid Uid - { - get - { - return _uid; - } - } - - /// - /// Returns true iff o is a QualifiedUid and the object class and uid match. - /// - public override bool Equals(Object o) - { - if (o is QualifiedUid) - { - QualifiedUid other = (QualifiedUid)o; - return (_objectClass.Equals(other._objectClass) && - _uid.Equals(other._uid)); - } - return false; - } - - /// - /// Returns a hash code based on uid - /// - public override int GetHashCode() - { - return _uid.GetHashCode(); - } - - /// - /// Returns a string representation acceptible for debugging. - /// - public override String ToString() - { - return SerializerUtil.SerializeXmlObject(this, false); - } - - } - #endregion - - #region ResultsHandler - /// - /// Encapsulate the handling of each object returned by the search. - /// - public delegate bool ResultsHandler(ConnectorObject obj); - #endregion - - #region Schema - /// - /// Determines the objects supported by a - /// . - /// - /// - /// The object is used to represent the basic objects that a - /// connector supports. This does not prevent a connector from supporting more. - /// Rather, this is informational for the caller of the connector to understand - /// a minimum support level. - /// The schema defines 4 primary data structures - /// - /// - /// Declared ObjectClasses (). - /// - /// - /// - /// Declared OperationOptionInfo (). - /// - /// - /// - /// Supported ObjectClasses by operation (). - /// - /// - /// - /// Supported OperationOptionInfo by operation(). - /// - /// - /// - /// TODO: add more to describe and what is expected from this call and how it is - /// used.. based on OperationalAttribute etc.. - /// - public sealed class Schema - { - private readonly ICollection _declaredObjectClasses; - private readonly ICollection _declaredOperationOptions; - private readonly IDictionary, ICollection> - _supportedObjectClassesByOperation; - private readonly IDictionary, ICollection> - _supportedOptionsByOperation; - - /// - /// Public only for serialization; please use - /// SchemaBuilder instead. - /// - /// - /// - public Schema(ICollection info, - ICollection options, - IDictionary, ICollection> supportedObjectClassesByOperation, - IDictionary, ICollection> supportedOptionsByOperation) - { - _declaredObjectClasses = CollectionUtil.NewReadOnlySet(info); - _declaredOperationOptions = CollectionUtil.NewReadOnlySet(options); - - //make read-only - { - IDictionary, ICollection> temp = - new Dictionary, ICollection>(); - foreach (KeyValuePair, ICollection> entry in - supportedObjectClassesByOperation) - { - SafeType op = - entry.Key; - ICollection resolvedClasses = - CollectionUtil.NewReadOnlySet(entry.Value); - temp[op] = resolvedClasses; - } - _supportedObjectClassesByOperation = CollectionUtil.AsReadOnlyDictionary(temp); - } - //make read-only - { - IDictionary, ICollection> temp = - new Dictionary, ICollection>(); - foreach (KeyValuePair, ICollection> entry in - supportedOptionsByOperation) - { - SafeType op = - entry.Key; - ICollection resolvedClasses = - CollectionUtil.NewReadOnlySet(entry.Value); - temp[op] = resolvedClasses; - } - _supportedOptionsByOperation = CollectionUtil.AsReadOnlyDictionary(temp); - } - } - - /// - /// Returns the set of object classes that are defined in the schema, regardless - /// of which operations support them. - /// - public ICollection ObjectClassInfo - { - get - { - return _declaredObjectClasses; - } - } - - /// - /// Returns the ObjectClassInfo for the given type. - /// - /// The type to find. - /// the ObjectClassInfo for the given type or null if not found. - public ObjectClassInfo FindObjectClassInfo(String type) - { - foreach (ObjectClassInfo info in _declaredObjectClasses) - { - if (info.Is(type)) - { - return info; - } - } - return null; - } - - /// - /// Returns the set of operation options that are defined in the schema, regardless - /// of which operations support them. - /// - /// The options defined in this schema. - public ICollection OperationOptionInfo - { - get - { - return _declaredOperationOptions; - } - } - - /// - /// Returns the OperationOptionInfo for the given name. - /// - /// The name to find. - /// the OperationOptionInfo for the given name or null if not found. - public OperationOptionInfo FindOperationOptionInfo(String name) - { - Assertions.NullCheck(name, "name"); - foreach (OperationOptionInfo info in _declaredOperationOptions) - { - if (info.Name.Equals(name)) - { - return info; - } - } - return null; - } - - /// - /// Returns the supported object classes for the given operation. - /// - /// The operation. - /// the supported object classes for the given operation. - public ICollection GetSupportedObjectClassesByOperation(SafeType apiop) - { - ICollection rv = - CollectionUtil.GetValue(_supportedObjectClassesByOperation, apiop, null); - if (rv == null) - { - ICollection empty = - CollectionUtil.NewReadOnlySet(); - - return empty; - } - else - { - return rv; - } - } - - /// - /// Returns the supported options for the given operation. - /// - /// The operation. - /// the supported options for the given operation. - public ICollection GetSupportedOptionsByOperation(SafeType apiop) - { - ICollection rv = - CollectionUtil.GetValue(_supportedOptionsByOperation, apiop, null); - if (rv == null) - { - ICollection empty = - CollectionUtil.NewReadOnlySet(); - return empty; - } - else - { - return rv; - } - } - - /// - /// Returns the set of object classes that apply to a particular operation. - /// - /// the set of object classes that apply to a particular operation. - public IDictionary, ICollection> SupportedObjectClassesByOperation - { - get - { - return _supportedObjectClassesByOperation; - } - } - /// - /// Returns the set of operation options that apply to a particular operation. - /// - /// the set of operation options that apply to a particular operation. - public IDictionary, ICollection> SupportedOptionsByOperation - { - get - { - return _supportedOptionsByOperation; - } - } - - - - public override int GetHashCode() - { - return CollectionUtil.GetHashCode(_declaredObjectClasses); - } - - public override bool Equals(object o) - { - Schema other = o as Schema; - if (other != null) - { - if (!CollectionUtil.Equals(ObjectClassInfo, other.ObjectClassInfo)) - { - return false; - } - if (!CollectionUtil.Equals(OperationOptionInfo, other.OperationOptionInfo)) - { - return false; - } - if (!CollectionUtil.Equals(_supportedObjectClassesByOperation, - other._supportedObjectClassesByOperation)) - { - return false; - } - if (!CollectionUtil.Equals(_supportedOptionsByOperation, - other._supportedOptionsByOperation)) - { - return false; - } - return true; - } - return false; - } - - public override string ToString() - { - return SerializerUtil.SerializeXmlObject(this, false); - } - } - #endregion - - #region SchemaBuilder - /// - /// Simple builder class to help facilitate creating a object. - /// - public sealed class SchemaBuilder - { - private readonly SafeType _connectorClass; - private readonly ICollection _declaredObjectClasses - = new HashSet(); - private readonly ICollection _declaredOperationOptions - = new HashSet(); - - private readonly IDictionary, ICollection> - _supportedObjectClassesByOperation = - new Dictionary, ICollection>(); - private readonly IDictionary, ICollection> - _supportedOptionsByOperation = - new Dictionary, ICollection>(); - - - /// - /// - public SchemaBuilder(SafeType connectorClass) - { - Assertions.NullCheck(connectorClass, "connectorClass"); - _connectorClass = connectorClass; - } - - /// - /// Adds another ObjectClassInfo to the schema. - /// - /// - /// Also, adds this - /// to the set of supported classes for every operation defined by - /// the Connector. - /// - /// - /// If already defined - public void DefineObjectClass(ObjectClassInfo info) - { - Assertions.NullCheck(info, "info"); - if (_declaredObjectClasses.Contains(info)) - { - throw new InvalidOperationException("ObjectClass already defined: " + - info.ObjectType); - } - _declaredObjectClasses.Add(info); - foreach (SafeType op in - FrameworkUtil.GetDefaultSupportedOperations(_connectorClass)) - { - ICollection oclasses = - CollectionUtil.GetValue(_supportedObjectClassesByOperation, op, null); - if (oclasses == null) - { - oclasses = new HashSet(); - _supportedObjectClassesByOperation[op] = oclasses; - } - oclasses.Add(info); - } - } - /// - /// Adds another OperationOptionInfo to the schema. - /// - /// - /// Also, adds this - /// to the set of supported options for every operation defined by - /// the Connector. - /// - public void DefineOperationOption(OperationOptionInfo info) - { - Assertions.NullCheck(info, "info"); - if (_declaredOperationOptions.Contains(info)) - { - throw new InvalidOperationException("OperationOption already defined: " + - info.Name); - } - _declaredOperationOptions.Add(info); - foreach (SafeType op in - FrameworkUtil.GetDefaultSupportedOperations(_connectorClass)) - { - ICollection oclasses = - CollectionUtil.GetValue(_supportedOptionsByOperation, op, null); - if (oclasses == null) - { - oclasses = new HashSet(); - _supportedOptionsByOperation[op] = oclasses; - } - oclasses.Add(info); - } - } - - /// - /// Adds another ObjectClassInfo to the schema. - /// - /// - /// Also, adds this - /// to the set of supported classes for every operation defined by - /// the Connector. - /// - /// If already defined - public void DefineObjectClass(String type, ICollection attrInfo) - { - ObjectClassInfoBuilder bld = new ObjectClassInfoBuilder(); - bld.ObjectType = type; - bld.AddAllAttributeInfo(attrInfo); - ObjectClassInfo obj = bld.Build(); - DefineObjectClass(obj); - } - - /// - /// Adds another OperationOptionInfo to the schema. - /// - /// - /// Also, adds this - /// to the set of supported options for every operation defined by - /// the Connector. - /// - /// If already defined - public void DefineOperationOption(String optionName, Type type) - { - OperationOptionInfoBuilder bld = new OperationOptionInfoBuilder(); - bld.Name = (optionName); - bld.OptionType = (type); - OperationOptionInfo info = bld.Build(); - DefineOperationOption(info); - } - - /// - /// Adds the given ObjectClassInfo as a supported ObjectClass for - /// the given operation. - /// - /// The SPI operation - /// The ObjectClassInfo - /// If the given ObjectClassInfo was - /// not already defined using . - public void AddSupportedObjectClass(SafeType op, - ObjectClassInfo def) - { - Assertions.NullCheck(op, "op"); - Assertions.NullCheck(def, "def"); - ICollection> apis = - FrameworkUtil.Spi2Apis(op); - if (!_declaredObjectClasses.Contains(def)) - { - throw new ArgumentException("ObjectClass " + def.ObjectType + - " not defined in schema."); - } - foreach (SafeType api in apis) - { - ICollection infos = - CollectionUtil.GetValue(_supportedObjectClassesByOperation, api, null); - if (infos == null) - { - throw new ArgumentException("Operation " + op + - " not implement by connector."); - } - if (infos.Contains(def)) - { - throw new ArgumentException("ObjectClass " + def.ObjectType + - " already supported for operation " + op); - } - infos.Add(def); - } - } - - /// - /// Removes the given ObjectClassInfo as a supported ObjectClass for - /// the given operation. - /// - /// The SPI operation - /// The ObjectClassInfo - /// If the given ObjectClassInfo was - /// not already defined using . - public void RemoveSupportedObjectClass(SafeType op, - ObjectClassInfo def) - { - Assertions.NullCheck(op, "op"); - Assertions.NullCheck(def, "def"); - ICollection> apis = - FrameworkUtil.Spi2Apis(op); - if (!_declaredObjectClasses.Contains(def)) - { - throw new ArgumentException("ObjectClass " + def.ObjectType + - " not defined in schema."); - } - foreach (SafeType api in apis) - { - ICollection infos = - CollectionUtil.GetValue(_supportedObjectClassesByOperation, api, null); - if (infos == null) - { - throw new ArgumentException("Operation " + op + - " not implement by connector."); - } - if (!infos.Contains(def)) - { - throw new ArgumentException("ObjectClass " + def.ObjectType - + " already removed for operation " + op); - } - infos.Remove(def); - } - } - /// - /// Adds the given OperationOptionInfo as a supported option for - /// the given operation. - /// - /// The SPI operation - /// The OperationOptionInfo - /// If the given OperationOptionInfo was - /// not already defined using . - public void AddSupportedOperationOption(SafeType op, - OperationOptionInfo def) - { - Assertions.NullCheck(op, "op"); - Assertions.NullCheck(def, "def"); - ICollection> apis = - FrameworkUtil.Spi2Apis(op); - if (!_declaredOperationOptions.Contains(def)) - { - throw new ArgumentException("OperationOption " + def.Name + - " not defined in schema."); - } - foreach (SafeType api in apis) - { - ICollection infos = - CollectionUtil.GetValue(_supportedOptionsByOperation, api, null); - if (infos == null) - { - throw new ArgumentException("Operation " + op + - " not implement by connector."); - } - if (infos.Contains(def)) - { - throw new ArgumentException("OperationOption " + def.Name + - " already supported for operation " + op); - } - infos.Add(def); - } - } - - /// - /// Removes the given OperationOptionInfo as a supported option for - /// the given operation. - /// - /// The SPI operation - /// The OperationOptionInfo - /// If the given OperationOptionInfo was - /// not already defined using . - public void RemoveSupportedOperationOption(SafeType op, - OperationOptionInfo def) - { - Assertions.NullCheck(op, "op"); - Assertions.NullCheck(def, "def"); - ICollection> apis = - FrameworkUtil.Spi2Apis(op); - if (!_declaredOperationOptions.Contains(def)) - { - throw new ArgumentException("OperationOption " + def.Name + - " not defined in schema."); - } - foreach (SafeType api in apis) - { - ICollection infos = - CollectionUtil.GetValue(_supportedOptionsByOperation, api, null); - if (infos == null) - { - throw new ArgumentException("Operation " + op + - " not implement by connector."); - } - if (!infos.Contains(def)) - { - throw new ArgumentException("OperationOption " + def.Name + - " already removed for operation " + op); - } - infos.Remove(def); - } - } - - /// - /// Clears the operation-specific supported classes. - /// - /// - /// Normally, when - /// you add an ObjectClass, using , - /// it is added to all operations. You may then remove those that you need - /// using . You - /// may wish, as an alternative to clear everything out and instead add using - /// . - /// - public void ClearSupportedObjectClassesByOperation() - { - foreach (ICollection values in - _supportedObjectClassesByOperation.Values) - { - values.Clear(); - } - } - /// - /// Clears the operation-specific supported options. - /// - /// - /// Normally, when - /// you add an OperationOptionInfo, using , - /// it is added to all operations. You may then remove those that you need - /// using . You - /// may wish, as an alternative to clear everything out and instead add using - /// . - /// - public void ClearSupportedOptionsByOperation() - { - foreach (ICollection values in - _supportedOptionsByOperation.Values) - { - values.Clear(); - } - } - - /// - /// Builds the object based on the s - /// added so far. - /// - /// new Schema object based on the info provided. - public Schema Build() - { - if (_declaredObjectClasses.Count == 0) - { - String ERR = "Must be at least one ObjectClassInfo object!"; - throw new InvalidOperationException(ERR); - } - return new Schema(_declaredObjectClasses, - _declaredOperationOptions, - _supportedObjectClassesByOperation, - _supportedOptionsByOperation); - } - } - #endregion - - #region Script - /// - /// Represents a script in a scripting language. - /// - /// 1.1 - public sealed class Script - { - - private readonly string scriptLanguage; - private readonly string scriptText; - - internal Script(string scriptLanguage, string scriptText) - { - Assertions.BlankCheck(scriptLanguage, "scriptLanguage"); - Assertions.NullCheck(scriptText, "scriptText"); // Allow empty text. - this.scriptLanguage = scriptLanguage; - this.scriptText = scriptText; - } - - /// - /// Returns the language of this script. - /// - /// the script language; never null. - public string ScriptLanguage - { - get - { - return scriptLanguage; - } - } - - /// - /// Returns the text of this script. - /// - /// the script text; never null. - public string ScriptText - { - get - { - return scriptText; - } - } - - public override int GetHashCode() - { - return scriptLanguage.GetHashCode() ^ scriptText.GetHashCode(); - } - - public override bool Equals(object obj) - { - if (obj is Script) - { - Script other = (Script)obj; - if (!scriptLanguage.Equals(other.scriptLanguage)) - { - return false; - } - if (!scriptText.Equals(other.scriptText)) - { - return false; - } - return true; - } - return false; - } - - public override string ToString() - { - // Text can be large, probably should not be included. - return "Script: " + scriptLanguage; - } - } - #endregion - - #region ScriptBuilder - /// - /// Builder for . - /// - public class ScriptBuilder - { - /// - /// Creates a new ScriptBuilder. - /// - public ScriptBuilder() - { - } - - /// - /// Gets/sets the language of the script. - /// - public string ScriptLanguage - { - get; - set; - } - - /// - /// Gets/sets the text of the script. - /// - public string ScriptText - { - get; - set; - } - - /// - /// Creates a Script. - /// - /// - /// Prior to calling this method the language - /// and the text should have been set. - /// - /// a new script; never null. - public Script Build() - { - return new Script(ScriptLanguage, ScriptText); - } - } - #endregion - - #region ScriptContext - /// - /// Encapsulates a script and all of its parameters. - /// - /// - /// - public sealed class ScriptContext - { - private readonly String _scriptLanguage; - private readonly String _scriptText; - private readonly IDictionary _scriptArguments; - - /// - /// Public only for serialization; please use . - /// - /// The script language. Must not be null. - /// The script text. Must not be null. - /// The script arguments. May be null. - public ScriptContext(String scriptLanguage, - String scriptText, - IDictionary scriptArguments) - { - - if (scriptLanguage == null) - { - throw new ArgumentException("Argument 'scriptLanguage' must be specified"); - } - if (scriptText == null) - { - throw new ArgumentException("Argument 'scriptText' must be specified"); - } - //clone script arguments and options - this serves two purposes - //1)makes sure everthing is serializable - //2)does a deep copy - IDictionary scriptArgumentsClone = (IDictionary)SerializerUtil.CloneObject(scriptArguments); - _scriptLanguage = scriptLanguage; - _scriptText = scriptText; - _scriptArguments = CollectionUtil.NewReadOnlyDictionary(scriptArgumentsClone); - } - - /// - /// Identifies the language in which the script is written - /// (e.g., bash, csh, - /// Perl4 or Python). - /// - /// The script language. - public String ScriptLanguage - { - get - { - return _scriptLanguage; - } - } - - /// - /// Returns the text (i.e., actual characters) of the script. - /// - /// The text of the script. - public String ScriptText - { - get - { - return _scriptText; - } - } - - /// - /// Returns a map of arguments to be passed to the script. - /// - /// - /// Values must be types that the framework can serialize. - /// See for a list of supported types. - /// - /// A map of arguments to be passed to the script. - public IDictionary ScriptArguments - { - get - { - return _scriptArguments; - } - } - - public override string ToString() - { - StringBuilder bld = new StringBuilder(); - bld.Append("ScriptContext: "); - // poor man's to string method. - IDictionary map = new Dictionary(); - map["Language"] = ScriptLanguage; - map["Text"] = ScriptText; - map["Arguments"] = ScriptArguments; - bld.Append(map.ToString()); - return bld.ToString(); - } - - } - #endregion - - #region ScriptContextBuilder - /// - /// Builds an . - /// - public sealed class ScriptContextBuilder - { - private String _scriptLanguage; - private String _scriptText; - private readonly IDictionary _scriptArguments = new - Dictionary(); - - /// - /// Creates an empty builder. - /// - public ScriptContextBuilder() - { - - } - - /// - /// Creates a builder with the required parameters specified. - /// - /// a string that identifies the language - /// in which the script is written - /// (e.g., bash, csh, - /// Perl4 or Python). - /// The text (i.e., actual characters) of the script. - public ScriptContextBuilder(String scriptLanguage, - String scriptText) - { - _scriptLanguage = scriptLanguage; - _scriptText = scriptText; - } - - /// - /// Identifies the language in which the script is written - /// (e.g., bash, csh, - /// Perl4 or Python). - /// - /// The script language. - public String ScriptLanguage - { - get - { - return _scriptLanguage; - } - set - { - _scriptLanguage = value; - } - } - - /// - /// Returns the actual characters of the script. - /// - /// the actual characters of the script. - public String ScriptText - { - get - { - return _scriptText; - } - set - { - _scriptText = value; - } - } - - /// - /// Adds or sets an argument to pass to the script. - /// - /// The name of the argument. Must not be null. - /// The value of the argument. Must be one of - /// type types that the framework can serialize. - /// - public ScriptContextBuilder AddScriptArgument(String name, Object value) - { - if (name == null) - { - throw new ArgumentException("Argument 'name' cannot be null."); - } - //don't validate value here - we do that implicitly when - //we clone in the constructor of ScriptRequest - _scriptArguments[name] = value; - return this; - } - - /// - /// Removes the given script argument. - /// - /// The name of the argument. Must not be null. - public ScriptContextBuilder RemoveScriptArgument(String name) - { - if (name == null) - { - throw new ArgumentException("Argument 'name' cannot be null."); - } - _scriptArguments.Remove(name); - return this; - } - - /// - /// Returns a mutable reference of the script arguments map. - /// - /// A mutable reference of the script arguments map. - public IDictionary ScriptArguments - { - get - { - //might as well be mutable since it's the builder and - //we don't want to deep copy anyway - return _scriptArguments; - } - } - - /// - /// Creates a ScriptContext. - /// - /// - /// The scriptLanguage and scriptText - /// must be set prior to calling this. - /// - /// The ScriptContext. - public ScriptContext Build() - { - return new ScriptContext(_scriptLanguage, - _scriptText, - _scriptArguments); - } - } - #endregion - - #region SyncDelta - /// - /// Represents a change to an object in a resource. - /// - /// - /// - public sealed class SyncDelta - { - private readonly SyncToken _token; - private readonly SyncDeltaType _deltaType; - private readonly Uid _previousUid; - private readonly Uid _uid; - private readonly ConnectorObject _object; - - /// - /// Creates a SyncDelata - /// - /// The token. Must not be null. - /// The delta. Must not be null. - /// The uid. Must not be null. - /// The object that has changed. May be null for delete. - internal SyncDelta(SyncToken token, SyncDeltaType deltaType, - Uid previousUid, Uid uid, - ConnectorObject obj) - { - Assertions.NullCheck(token, "token"); - Assertions.NullCheck(deltaType, "deltaType"); - Assertions.NullCheck(uid, "uid"); - - //do not allow previous Uid for anything else than create or update - if (previousUid != null && deltaType != SyncDeltaType.CREATE_OR_UPDATE) - { - throw new ArgumentException("The previous Uid can only be specified for create or update."); - } - - //only allow null object for delete - if (obj == null && - deltaType != SyncDeltaType.DELETE) - { - throw new ArgumentException("ConnectorObject must be specified for anything other than delete."); - } - - //if object not null, make sure its Uid - //matches - if (obj != null) - { - if (!uid.Equals(obj.Uid)) - { - throw new ArgumentException("Uid does not match that of the object."); - } - } - - _token = token; - _deltaType = deltaType; - _previousUid = previousUid; - _uid = uid; - _object = obj; - - } - - /// - /// If the change described by this SyncDelta modified the - /// object's Uid, this method returns the Uid before the change. - /// - /// - /// Not - /// all resources can determine the previous Uid, so this method can - /// return null. - /// - /// the previous Uid or null if it could not be determined - /// or the change did not modify the Uid. - public Uid PreviousUid - { - get - { - return _previousUid; - } - } - - /// - /// Returns the Uid of the object that changed. - /// - /// the Uid of the object that changed. - public Uid Uid - { - get - { - return _uid; - } - } - - /// - /// Returns the connector object that changed. - /// - /// - /// This - /// may be null in the case of delete. - /// - /// The object or possibly null if this - /// represents a delete. - public ConnectorObject Object - { - get - { - return _object; - } - } - - /// - /// Returns the SyncToken of the object that changed. - /// - /// the SyncToken of the object that changed. - public SyncToken Token - { - get - { - return _token; - } - } - - /// - /// Returns the type of the change the occured. - /// - /// The type of change that occured. - public SyncDeltaType DeltaType - { - get - { - return _deltaType; - } - } - - - public override String ToString() - { - IDictionary values = new Dictionary(); - values["Token"] = _token; - values["DeltaType"] = _deltaType; - values["PreviousUid"] = _previousUid; - values["Uid"] = _uid; - values["Object"] = _object; - return values.ToString(); - } - - public override int GetHashCode() - { - return _uid.GetHashCode(); - } - - public override bool Equals(Object o) - { - if (o is SyncDelta) - { - SyncDelta other = (SyncDelta)o; - if (!_token.Equals(other._token)) - { - return false; - } - if (!_deltaType.Equals(other._deltaType)) - { - return false; - } - if (_previousUid == null) - { - if (other._previousUid != null) - { - return false; - } - } - else if (!_previousUid.Equals(other._previousUid)) - { - return false; - } - if (!_uid.Equals(other._uid)) - { - return false; - } - if (_object == null) - { - if (other._object != null) - { - return false; - } - } - else if (!_object.Equals(other._object)) - { - return false; - } - return true; - } - return false; - } - } - #endregion - - #region SyncDeltaBuilder - /// - /// Builder for . - /// - public sealed class SyncDeltaBuilder - { - private SyncToken _token; - private SyncDeltaType _deltaType; - private Uid _previousUid; - private Uid _uid; - private ConnectorObject _object; - - /// - /// Create a new SyncDeltaBuilder - /// - public SyncDeltaBuilder() - { - - } - - /// - /// Creates a new SyncDeltaBuilder whose - /// values are initialized to those of the delta. - /// - /// The original delta. - public SyncDeltaBuilder(SyncDelta delta) - { - _token = delta.Token; - _deltaType = delta.DeltaType; - _previousUid = delta.PreviousUid; - _uid = delta.Uid; - _object = delta.Object; - } - - /// - /// Returns the SyncToken of the object that changed. - /// - /// the SyncToken of the object that changed. - public SyncToken Token - { - get - { - return _token; - } - set - { - _token = value; - } - } - - /// - /// Returns the type of the change that occurred. - /// - /// The type of change that occurred. - public SyncDeltaType DeltaType - { - get - { - return _deltaType; - } - set - { - _deltaType = value; - } - } - - /// - /// Returns the Uid before the change. - /// - /// the Uid before the change. - public Uid PreviousUid - { - get - { - return _previousUid; - } - set - { - _previousUid = value; - } - } - - /// - /// Returns the Uid of the object that changed. - /// - /// - /// Note that this is implicitly set when you call - /// . - /// - /// the Uid of the object that changed. - public Uid Uid - { - get - { - return _uid; - } - set - { - _uid = value; - } - } - - /// - /// Returns the object that changed. - /// - /// - /// Sets the object that changed and implicitly - /// sets Uid if object is not null. - /// - /// The object that changed. May be null for - /// deletes. - public ConnectorObject Object - { - get - { - return _object; - } - set - { - _object = value; - if (value != null) - { - _uid = value.Uid; - } - } - } - - /// - /// Creates a SyncDelta. - /// - /// - /// Prior to calling the following must be specified: - /// - /// - /// (for anything other than delete) - /// - /// - /// - /// (this is implictly set when calling ) - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public SyncDelta Build() - { - return new SyncDelta(_token, _deltaType, _previousUid, _uid, _object); - } - } - #endregion - - #region SyncDeltaType - /// - /// The type of change. - /// - public enum SyncDeltaType - { - /// - /// The change represents either a create or an update in - /// the resource. - /// - /// - /// These are combined into a single value because: - /// - /// - /// Many resources will not be able to distinguish a create from an update. - /// Those that have an audit log will be able to. However, many implementations - /// will only have the current record and a modification timestamp. - /// - /// - /// - /// Regardless of whether or not the resource can distinguish the two cases, - /// the application needs to distinguish. - /// - /// - /// - /// - CREATE_OR_UPDATE, - - /// - /// The change represents a DELETE in the resource - /// - DELETE - } - #endregion - - #region SyncResultsHandler - /// - /// Called to handle a delta in the stream. - /// - /// - /// Will be called multiple times, - /// once for each result. Although a callback, this is still invoked - /// synchronously. That is, it is guaranteed that following a call to - /// no - /// more invocations to will be performed. - /// - /// The change - /// True iff the application wants to continue processing more - /// results. - /// If the application encounters an exception. This will stop - /// the interation and the exception will be propogated back to - /// the application. - public delegate bool SyncResultsHandler(SyncDelta delta); - #endregion - - #region SyncToken - /// - /// Abstract "place-holder" for synchronization. - /// - /// - /// The application must not make - /// any attempt to interpret the value of the token. From the standpoint of the - /// application the token is merely a black-box. The application may only persist - /// the value of the token for use on subsequent synchronization requests. - /// - /// What this token represents is entirely connector-specific. On some connectors - /// this might be a last-modified value. On others, it might be a unique ID of a - /// log table entry. On others such as JMS, this might be a dummy value since - /// JMS itself keeps track of the state of the sync. - /// - /// - public sealed class SyncToken - { - - private Object _value; - - /// - /// Creates a new - /// - /// May not be null. TODO: define set of allowed value types - /// (currently same as set of allowed attribute values). - public SyncToken(Object value) - { - Assertions.NullCheck(value, "value"); - FrameworkUtil.CheckAttributeValue(value); - _value = value; - } - - /// - /// Returns the value for the token. - /// - /// The value for the token. - public Object Value - { - get - { - return _value; - } - } - - public override String ToString() - { - return "SyncToken: " + _value.ToString(); - } - - public override int GetHashCode() - { - return CollectionUtil.GetHashCode(_value); - } - - public override bool Equals(Object o) - { - if (o is SyncToken) - { - SyncToken other = (SyncToken)o; - return CollectionUtil.Equals(_value, other._value); - } - return false; - } - - - } - #endregion - - #region Uid - public sealed class Uid : ConnectorAttribute - { - - public static readonly string NAME = ConnectorAttributeUtil.CreateSpecialName("UID"); - - public Uid(String val) - : base(NAME, CollectionUtil.NewReadOnlyList(Check(val))) - { - } - private static String Check(String value) - { - if (StringUtil.IsBlank(value)) - { - String ERR = "Uid value must not be blank!"; - throw new ArgumentException(ERR); - } - return value; - } - /// - /// The single value of the attribute that is the unique id of an object. - /// - /// value that identifies an object. - public String GetUidValue() - { - return ConnectorAttributeUtil.GetStringValue(this); - } - } - #endregion - - #region ConnectorAttributesAccessor - /// - /// Attributes Accessor convenience methods for accessing attributes. - /// - /// - /// This class wraps a set of attributes to make lookup faster than the - /// method, since that method must - /// re-create the map each time. - /// - /// Warren Strange - public class ConnectorAttributesAccessor - { - - ICollection _attrs; - IDictionary _attrMap; - - public ConnectorAttributesAccessor(ICollection attrs) - { - _attrs = attrs; - _attrMap = ConnectorAttributeUtil.ToMap(attrs); - } - - /// - /// Find the named attribute - /// - /// - - /// the attribute name to search for - /// the Attribute, or null if not found. - public ConnectorAttribute Find(String name) - { - return CollectionUtil.GetValue(_attrMap, name, null); - } - - /// - /// Get the attribute from the set of attributes. - /// - /// the attribute in the set. - public Name GetName() - { - return (Name)Find(Name.NAME); - } - - /// - /// Return the enabled status of the account. - /// - /// - /// If the ENABLE operational attribute is present, it's value takes - /// precedence over the current value. If it is missing, the currentlyEnabled - /// status is returned instead. - /// - /// the default state if enable is not found. - /// true if the account is enabled, false otherwise - public bool GetEnabled(bool dflt) - { - bool e = dflt; - ConnectorAttribute enable = Find(OperationalAttributes.ENABLE_NAME); - if (enable != null) - { - e = ConnectorAttributeUtil.GetBooleanValue(enable).Value; - } - return e; - } - - /// - /// Get the password as a GuardeString - /// - /// the password as a guarded String - public GuardedString GetPassword() - { - ConnectorAttribute a = Find(OperationalAttributes.PASSWORD_NAME); - return a == null ? null : ConnectorAttributeUtil.GetGuardedStringValue(a); - } - - /// - /// Return a list of attributes - /// - /// - - /// name of attribute to search for. - /// The List (generic object) iff it exists otherwise null. - public IList FindList(String name) - { - ConnectorAttribute a = Find(name); - return (a == null) ? null : a.Value; - } - - /// - /// Return the multivalued attribute as a list of strings. - /// - /// - /// This will throw a - /// ClassCastException if the underlying attribute list is not of type - /// String. - /// - /// the name of the attribute to search for - /// a List of String values for the attribute - public IList FindStringList(String name) - { - IList l = FindList(name); - if (l != null) - { - IList ret = new List(l.Count); - foreach (object o in l) - { - ret.Add((String)o); - } - return ret; - } - return null; - } - - /// - /// Determines if the set as the attribute specified. - /// - /// attribute name - /// true if the named attribute exists, false otherwise - public bool HasAttribute(String name) - { - return Find(name) != null; - } - - /// - /// Get the string value from the specified (single-valued) attribute. - /// - /// Attribute from which to retrieve the long value. - /// null if the value is null otherwise the long value for the - /// attribute. - /// iff the object in the attribute is not an long. - /// iff the attribute is a multi-valued (rather than - /// single-valued). - public String FindString(String name) - { - ConnectorAttribute a = Find(name); - return a == null ? null : ConnectorAttributeUtil.GetStringValue(a); - } - - /// - /// Get the integer value from the specified (single-valued) attribute. - /// - /// Attribute from which to retrieve the long value. - /// null if the value is null otherwise the long value for the - /// attribute. - /// iff the object in the attribute is not an long. - /// iff the attribute is a multi-valued (rather than - /// single-valued). - public int? FindInteger(String name) - { - ConnectorAttribute a = Find(name); - return (a == null) ? null : ConnectorAttributeUtil.GetIntegerValue(a); - } - - /// - /// Get the long value from the specified (single-valued) attribute. - /// - /// Attribute from which to retrieve the long value. - /// null if the value is null otherwise the long value for the - /// attribute. - /// iff the object in the attribute is not an long. - /// iff the attribute is a multi-valued (rather than - /// single-valued). - public long? FindLong(String name) - { - ConnectorAttribute a = Find(name); - return a == null ? null : ConnectorAttributeUtil.GetLongValue(a); - } - - /// - /// Get the date value from the specified (single-valued) attribute that - /// contains a long. - /// - /// Attribute from which to retrieve the date value. - /// null if the value is null otherwise the date value for the - /// attribute. - /// iff the object in the attribute is not an long. - /// iff the attribute is a multi-valued (rather than - /// single-valued). - public DateTime? FindDateTime(String name) - { - ConnectorAttribute a = Find(name); - return a == null ? null : ConnectorAttributeUtil.GetDateTimeValue(a); - } - - /// - /// Get the integer value from the specified (single-valued) attribute. - /// - /// Attribute from which to retrieve the integer value. - /// null if the value is null otherwise the integer value for the - /// attribute. - /// iff the object in the attribute is not an integer. - /// iff the attribute is a multi-valued (rather than - /// single-valued).. - public double? FindDouble(String name) - { - ConnectorAttribute a = Find(name); - return a == null ? null : ConnectorAttributeUtil.GetDoubleValue(a); - } - - /// - /// Get the boolean value from the specified (single-valued) attribute. - /// - /// Attribute from which to retrieve the boolean value. - /// null if the value is null otherwise the boolean value for the - /// attribute. - /// iff the object in the attribute is not an . - /// iff the attribute is a multi-valued (rather than - /// single-valued). - public bool? FindBoolean(String name) - { - ConnectorAttribute a = Find(name); - return a == null ? null : ConnectorAttributeUtil.GetBooleanValue(a); - } - } - #endregion - - #region CultureInfoCache - internal static class CultureInfoCache - { - private static readonly object LOCK = new Object(); - private static CultureInfo _instance; - - public static CultureInfo Instance - { - get - { - lock (LOCK) - { - if (_instance == null) - { - _instance = CultureInfo.CurrentCulture; - if (_instance == null) - { - _instance = CultureInfo.InstalledUICulture; - } - } - return _instance; - } - } - } - } - #endregion -} \ No newline at end of file diff --git a/Framework/CommonObjectsFilter.cs b/Framework/CommonObjectsFilter.cs deleted file mode 100644 index 380102d..0000000 --- a/Framework/CommonObjectsFilter.cs +++ /dev/null @@ -1,1471 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Text; -using System.Collections.Generic; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Framework.Common.Objects; -namespace Org.IdentityConnectors.Framework.Common.Objects.Filters -{ - #region AbstractFilterTranslator - /// - /// Base class to make it easier to implement Search. - /// - /// - /// A search filter may contain operators (such as 'contains' or 'in') - /// or may contain logical operators (such as 'AND', 'OR' or 'NOT') - /// that a connector cannot implement using the native API - /// of the target system or application. - /// A connector developer should subclass AbstractFilterTranslator - /// in order to declare which filter operations the connector does support. - /// This allows the FilterTranslator instance to analyze - /// a specified search filter and reduce the filter to its most efficient form. - /// The default (and worst-case) behavior is to return a null expression, - /// which means that the connector should return "everything" - /// (that is, should return all values for every requested attribute) - /// and rely on the common code in the framework to perform filtering. - /// This "fallback" behavior is good (in that it ensures consistency - /// of search behavior across connector implementations) but it is - /// obviously better for performance and scalability if each connector - /// performs as much filtering as the native API of the target can support. - /// - /// A subclass should override each of the following methods where possible: - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// Translation can then be performed using . - /// - /// - /// - /// - /// The result type of the translator. Commonly this will - /// be a string, but there are cases where you might need to return - /// a more complex data structure. For example if you are building a SQL - /// query, you will need not *just* the base WHERE clause but a list - /// of tables that need to be joined together. - abstract public class AbstractFilterTranslator : FilterTranslator - where T : class - { - /// - /// Main method to be called to translate a filter - /// - /// The filter to translate. - /// The list of queries to be performed. The list - /// size() may be one of the following: - /// - /// - /// 0 - This - /// signifies fetch everything. This may occur if your filter - /// was null or one of your create* methods returned null. - /// - /// - /// - /// 1 - List contains a single query that will return the results from the filter. - /// Note that the results may be a superset of those specified by - /// the filter in the case that one of your create* methods returned null. - /// That is OK from a behavior standpoint since ConnectorFacade performs - /// a second level of filtering. However it is undesirable from a performance standpoint. - /// - /// - /// - /// >1 - List contains multiple queries that must be performed in order to - /// meet the filter that was passed in. Note that this only occurs if your - /// method can return null. If this happens, it - /// is the responsibility of the connector implementor to perform each query - /// and combine the results. In order to eliminate duplicates, the connector - /// implementation must keep an in-memory HashSet of those UID - /// that have been visited thus far. This will not scale well if your - /// result sets are large. Therefore it is recommended that if - /// at all possible you implement - /// - /// - /// - public IList Translate(Filter filter) - { - if (filter == null) - { - return new List(); - } - //this must come first - filter = NormalizeNot(filter); - filter = SimplifyAndDistribute(filter); - //might have simplified it to the everything filter - if (filter == null) - { - return new List(); - } - IList result = TranslateInternal(filter); - //now "optimize" - we can eliminate exact matches at least - HashSet set = new HashSet(); - IList optimized = new List(result.Count); - foreach (T obj in result) - { - if (set.Add(obj)) - { - optimized.Add(obj); - } - } - return optimized; - } - - /// - /// Pushes Not's so that they are just before the leaves of the tree - /// - private Filter NormalizeNot(Filter filter) - { - if (filter is AndFilter) - { - AndFilter af = (AndFilter)filter; - return new AndFilter(NormalizeNot(af.Left), - NormalizeNot(af.Right)); - } - else if (filter is OrFilter) - { - OrFilter of = (OrFilter)filter; - return new OrFilter(NormalizeNot(of.Left), - NormalizeNot(of.Right)); - } - else if (filter is NotFilter) - { - NotFilter nf = (NotFilter)filter; - return Negate(NormalizeNot(nf.Filter)); - } - else - { - return filter; - } - } - - /// - /// Given a filter, create a filter representing its negative. - /// - /// - /// This is used by normalizeNot. - /// - private Filter Negate(Filter filter) - { - if (filter is AndFilter) - { - AndFilter af = (AndFilter)filter; - return new OrFilter(Negate(af.Left), - Negate(af.Right)); - } - else if (filter is OrFilter) - { - OrFilter of = (OrFilter)filter; - return new AndFilter(Negate(of.Left), - Negate(of.Right)); - } - else if (filter is NotFilter) - { - NotFilter nf = (NotFilter)filter; - return nf.Filter; - } - else - { - return new NotFilter(filter); - } - } - - /// - /// Simultaneously prunes those portions of the - /// filter than cannot be implemented and distributes - /// Ands over Ors where needed if the resource does not - /// implement Or. - /// - /// Nots must already be normalized - /// a simplified filter or null to represent the - /// "everything" filter. - private Filter SimplifyAndDistribute(Filter filter) - { - if (filter is AndFilter) - { - AndFilter af = (AndFilter)filter; - Filter simplifiedLeft = - SimplifyAndDistribute(af.Left); - Filter simplifiedRight = - SimplifyAndDistribute(af.Right); - if (simplifiedLeft == null) - { - //left is "everything" - just return the right - return simplifiedRight; - } - else if (simplifiedRight == null) - { - //right is "everything" - just return the left - return simplifiedLeft; - } - else - { - //simulate translation of the left and right - //to see where we end up - IList leftExprs = - TranslateInternal(simplifiedLeft); - IList rightExprs = - TranslateInternal(simplifiedRight); - if (leftExprs.Count == 0) - { - //This can happen only when one of the create* methods - //is inconsistent from one invocation to the next - //(simplifiedLeft should have been null - //in the previous 'if' above). - throw new InvalidOperationException("Translation method is inconsistent: " + leftExprs); - } - if (rightExprs.Count == 0) - { - //This can happen only when one of the create* methods - //is inconsistent from one invocation to the next - //(simplifiedRight should have been null - //in the previous 'if' above). - throw new InvalidOperationException("Translation method is inconsistent: " + rightExprs); - } - - //Simulate ANDing each pair(left,right). - //If all of them return null (i.e., "everything"), - //then the request cannot be filtered. - bool anyAndsPossible = false; - foreach (T leftExpr in leftExprs) - { - foreach (T rightExpr in rightExprs) - { - T test = CreateAndExpression( - leftExpr, - rightExpr); - if (test != null) - { - anyAndsPossible = true; - break; - } - } - if (anyAndsPossible) - { - break; - } - } - - //If no AND filtering is possible, - //return whichever of left or right - //contains the fewest expressions. - if (!anyAndsPossible) - { - if (leftExprs.Count <= rightExprs.Count) - { - return simplifiedLeft; - } - else - { - return simplifiedRight; - } - } - - //Since AND filtering is possible for at least - //one expression, let's distribute. - if (leftExprs.Count > 1) - { - //The left can contain more than one expression - //only if the left-hand side is an unimplemented OR. - //Distribute our AND to the left. - OrFilter left = (OrFilter)simplifiedLeft; - OrFilter newFilter = - new OrFilter(new AndFilter(left.Left, - simplifiedRight), - new AndFilter(left.Right, - simplifiedRight)); - return SimplifyAndDistribute(newFilter); - } - else if (rightExprs.Count > 1) - { - //The right can contain more than one expression - //only if the right-hand side is an unimplemented OR. - //Distribute our AND to the right. - OrFilter right = (OrFilter)simplifiedRight; - OrFilter newFilter = - new OrFilter(new AndFilter(simplifiedLeft, - right.Left), - new AndFilter(simplifiedLeft, - right.Right)); - return SimplifyAndDistribute(newFilter); - } - else - { - //Each side contains exactly one expression - //and the translator does implement AND - //(anyAndsPossible must be true - //for them to have hit this branch). - if (!anyAndsPossible) - { - throw new Exception("expected anyAndsPossible"); - } - return new AndFilter(simplifiedLeft, simplifiedRight); - } - } - } - else if (filter is OrFilter) - { - OrFilter of = (OrFilter)filter; - Filter simplifiedLeft = - SimplifyAndDistribute(of.Left); - Filter simplifiedRight = - SimplifyAndDistribute(of.Right); - //If either left or right reduces to "everything", - //then simplify the OR to "everything". - if (simplifiedLeft == null || simplifiedRight == null) - { - return null; - } - //otherwise - return new OrFilter(simplifiedLeft, - simplifiedRight); - } - else - { - //Otherwise, it's a NOT(LEAF) or a LEAF. - //Simulate creating it. - T expr = CreateLeafExpression(filter); - if (expr == null) - { - //If the expression cannot be implemented, - //return the "everything" filter. - return null; - } - else - { - //Otherwise, return the filter. - return filter; - } - } - } - - /// - /// Translates the filter into a list of expressions. - /// - /// - /// The filter must have already been transformed - /// using normalizeNot followed by a simplifyAndDistribute. - /// - /// A filter (normalized, simplified, and distibuted) - /// A list of expressions or empty list for everything. - private IList TranslateInternal(Filter filter) - { - if (filter is AndFilter) - { - T result = TranslateAnd((AndFilter)filter); - IList rv = new List(); - if (result != null) - { - rv.Add(result); - } - return rv; - } - else if (filter is OrFilter) - { - return TranslateOr((OrFilter)filter); - } - else - { - //otherwise it's either a leaf or a NOT (leaf) - T expr = CreateLeafExpression(filter); - IList exprs = new List(); - if (expr != null) - { - exprs.Add(expr); - } - return exprs; - } - } - - private T TranslateAnd(AndFilter filter) - { - IList leftExprs = TranslateInternal(filter.Left); - IList rightExprs = TranslateInternal(filter.Right); - if (leftExprs.Count != 1) - { - //this can happen only if one of the create* methods - //is inconsistent from one invocation to the next - //(at this point we've already been simplified and - //distributed). - throw new InvalidOperationException("Translation method is inconsistent: " + leftExprs); - } - if (rightExprs.Count != 1) - { - //this can happen only if one of the create* methods - //is inconsistent from one invocation to the next - //(at this point we've already been simplified and - //distributed). - throw new InvalidOperationException("Translation method is inconsistent: " + rightExprs); - } - T rv = CreateAndExpression(leftExprs[0], rightExprs[0]); - if (rv == null) - { - //This could happen only if we're inconsistent - //(since the simplify logic already should have removed - //any expression that cannot be filtered). - throw new InvalidOperationException("createAndExpression is inconsistent"); - } - return rv; - } - - private IList TranslateOr(OrFilter filter) - { - IList leftExprs = TranslateInternal(filter.Left); - IList rightExprs = TranslateInternal(filter.Right); - if (leftExprs.Count == 0) - { - //This can happen only if one of the create* methods - //is inconsistent from one invocation to the next. - throw new InvalidOperationException("Translation method is inconsistent"); - } - if (rightExprs.Count == 0) - { - //This can happen only if one of the create* methods - //methods is inconsistent from on invocation to the next. - throw new InvalidOperationException("Translation method is inconsistent"); - } - if (leftExprs.Count == 1 && rightExprs.Count == 1) - { - //If each side contains exactly one expression, - //try to create a combined expression. - T val = CreateOrExpression(leftExprs[0], rightExprs[0]); - if (val != null) - { - IList rv = new List(); - rv.Add(val); - return rv; - } - //Otherwise, fall through - } - - //Return a list of queries from the left and from the right - IList rv2 = new List(leftExprs.Count + rightExprs.Count); - CollectionUtil.AddAll(rv2, leftExprs); - CollectionUtil.AddAll(rv2, rightExprs); - return rv2; - } - - /// - /// Creates an expression for a LEAF or a NOT(leaf) - /// - /// Must be either a leaf or a NOT(leaf) - /// The expression - private T CreateLeafExpression(Filter filter) - { - Filter leafFilter; - bool not; - if (filter is NotFilter) - { - NotFilter nf = (NotFilter)filter; - leafFilter = nf.Filter; - not = true; - } - else - { - leafFilter = filter; - not = false; - } - T expr = CreateLeafExpression(leafFilter, not); - return expr; - } - - /// - /// Creates a Leaf expression - /// - /// Must be a leaf expression - /// Is ! to be applied to the leaf expression - /// The expression or null (for everything) - private T CreateLeafExpression(Filter filter, bool not) - { - if (filter is ContainsFilter) - { - return CreateContainsExpression((ContainsFilter)filter, not); - } - else if (filter is EndsWithFilter) - { - return CreateEndsWithExpression((EndsWithFilter)filter, not); - } - else if (filter is EqualsFilter) - { - return CreateEqualsExpression((EqualsFilter)filter, not); - } - else if (filter is GreaterThanFilter) - { - return CreateGreaterThanExpression((GreaterThanFilter)filter, not); - } - else if (filter is GreaterThanOrEqualFilter) - { - return CreateGreaterThanOrEqualExpression((GreaterThanOrEqualFilter)filter, not); - } - else if (filter is LessThanFilter) - { - return CreateLessThanExpression((LessThanFilter)filter, not); - } - else if (filter is LessThanOrEqualFilter) - { - return CreateLessThanOrEqualExpression((LessThanOrEqualFilter)filter, not); - } - else if (filter is StartsWithFilter) - { - return CreateStartsWithExpression((StartsWithFilter)filter, not); - } - else if (filter is ContainsAllValuesFilter) - { - return CreateContainsAllValuesExpression((ContainsAllValuesFilter)filter, not); - } - else - { - //unrecognized expression - nothing we can do - return null; - } - } - - /// - /// Should be overridden by subclasses to create an AND expression - /// if the native resource supports AND. - /// - /// The left expression. Will never be null. - /// The right expression. Will never be null. - /// The AND expression. A return value of null means - /// a native AND query cannot be created for the given expressions. - /// In this case, the resulting query will consist of the - /// leftExpression only. - protected virtual T CreateAndExpression(T leftExpression, T rightExpression) - { - return null; - } - - /// - /// Should be overridden by subclasses to create an OR expression - /// if the native resource supports OR. - /// - /// The left expression. Will never be null. - /// The right expression. Will never be null. - /// The OR expression. A return value of null means - /// a native OR query cannot be created for the given expressions. - /// In this case, may return multiple queries, each - /// of which must be run and results combined. - protected virtual T CreateOrExpression(T leftExpression, T rightExpression) - { - return null; - } - - /// - /// Should be overridden by subclasses to create a CONTAINS expression - /// if the native resource supports CONTAINS. - /// - /// The contains filter. Will never be null. - /// True if this should be a NOT CONTAINS - /// The CONTAINS expression. A return value of null means - /// a native CONTAINS query cannot be created for the given filter. - /// In this case, may return an empty query set, meaning - /// fetch everything. The filter will be re-applied in memory - /// to the resulting object stream. This does not scale well, so - /// if possible, you should implement this method. - protected virtual T CreateContainsExpression(ContainsFilter filter, bool not) - { - return null; - } - - /// - /// Should be overridden by subclasses to create a ENDS-WITH expression - /// if the native resource supports ENDS-WITH. - /// - /// The contains filter. Will never be null. - /// True if this should be a NOT ENDS-WITH - /// The ENDS-WITH expression. A return value of null means - /// a native ENDS-WITH query cannot be created for the given filter. - /// In this case, may return an empty query set, meaning - /// fetch everything. The filter will be re-applied in memory - /// to the resulting object stream. This does not scale well, so - /// if possible, you should implement this method. - protected virtual T CreateEndsWithExpression(EndsWithFilter filter, bool not) - { - return null; - } - - /// - /// Should be overridden by subclasses to create a EQUALS expression - /// if the native resource supports EQUALS. - /// - /// The contains filter. Will never be null. - /// True if this should be a NOT EQUALS - /// The EQUALS expression. A return value of null means - /// a native EQUALS query cannot be created for the given filter. - /// In this case, may return an empty query set, meaning - /// fetch everything. The filter will be re-applied in memory - /// to the resulting object stream. This does not scale well, so - /// if possible, you should implement this method. - protected virtual T CreateEqualsExpression(EqualsFilter filter, bool not) - { - return null; - } - - /// - /// Should be overridden by subclasses to create a GREATER-THAN expression - /// if the native resource supports GREATER-THAN. - /// - /// The contains filter. Will never be null. - /// True if this should be a NOT GREATER-THAN - /// The GREATER-THAN expression. A return value of null means - /// a native GREATER-THAN query cannot be created for the given filter. - /// In this case, may return an empty query set, meaning - /// fetch everything. The filter will be re-applied in memory - /// to the resulting object stream. This does not scale well, so - /// if possible, you should implement this method. - protected virtual T CreateGreaterThanExpression(GreaterThanFilter filter, bool not) - { - return null; - } - - /// - /// Should be overridden by subclasses to create a GREATER-THAN-EQUAL expression - /// if the native resource supports GREATER-THAN-EQUAL. - /// - /// The contains filter. Will never be null. - /// True if this should be a NOT GREATER-THAN-EQUAL - /// The GREATER-THAN-EQUAL expression. A return value of null means - /// a native GREATER-THAN-EQUAL query cannot be created for the given filter. - /// In this case, may return an empty query set, meaning - /// fetch everything. The filter will be re-applied in memory - /// to the resulting object stream. This does not scale well, so - /// if possible, you should implement this method. - protected virtual T CreateGreaterThanOrEqualExpression(GreaterThanOrEqualFilter filter, bool not) - { - return null; - } - - /// - /// Should be overridden by subclasses to create a LESS-THAN expression - /// if the native resource supports LESS-THAN. - /// - /// The contains filter. Will never be null. - /// True if this should be a NOT LESS-THAN - /// The LESS-THAN expression. A return value of null means - /// a native LESS-THAN query cannot be created for the given filter. - /// In this case, may return an empty query set, meaning - /// fetch everything. The filter will be re-applied in memory - /// to the resulting object stream. This does not scale well, so - /// if possible, you should implement this method. - protected virtual T CreateLessThanExpression(LessThanFilter filter, bool not) - { - return null; - } - - /// - /// Should be overridden by subclasses to create a LESS-THAN-EQUAL expression - /// if the native resource supports LESS-THAN-EQUAL. - /// - /// The contains filter. Will never be null. - /// True if this should be a NOT LESS-THAN-EQUAL - /// The LESS-THAN-EQUAL expression. A return value of null means - /// a native LESS-THAN-EQUAL query cannot be created for the given filter. - /// In this case, may return an empty query set, meaning - /// fetch everything. The filter will be re-applied in memory - /// to the resulting object stream. This does not scale well, so - /// if possible, you should implement this method. - protected virtual T CreateLessThanOrEqualExpression(LessThanOrEqualFilter filter, bool not) - { - return null; - } - - /// - /// Should be overridden by subclasses to create a STARTS-WITH expression - /// if the native resource supports STARTS-WITH. - /// - /// The contains filter. Will never be null. - /// True if this should be a NOT STARTS-WITH - /// The STARTS-WITH expression. A return value of null means - /// a native STARTS-WITH query cannot be created for the given filter. - /// In this case, may return an empty query set, meaning - /// fetch everything. The filter will be re-applied in memory - /// to the resulting object stream. This does not scale well, so - /// if possible, you should implement this method. - protected virtual T CreateStartsWithExpression(StartsWithFilter filter, bool not) - { - return null; - } - - protected virtual T CreateContainsAllValuesExpression(ContainsAllValuesFilter filter, bool not) - { - return null; - } - } - #endregion - - #region AndFilter - public sealed class AndFilter : CompositeFilter - { - /// - /// And the the left and right filters. - /// - public AndFilter(Filter left, Filter right) - : base(left, right) - { - } - - /// - /// Ands the left and right filters. - /// - /// - public override bool Accept(ConnectorObject obj) - { - return Left.Accept(obj) && Right.Accept(obj); - } - - public override string ToString() - { - StringBuilder bld = new StringBuilder(); - bld.Append("AND: ").Append(Left).Append(", ").Append(Right); - return bld.ToString(); - } - } - #endregion - - #region AttributeFilter - public abstract class AttributeFilter : Filter - { - private readonly ConnectorAttribute _attribute; - - /// - /// Root filter for Attribute testing.. - /// - internal AttributeFilter(ConnectorAttribute attribute) - { - _attribute = attribute; - if (attribute == null) - { - throw new ArgumentException("Attribute not be null!"); - } - } - - /// - /// Get the internal attribute. - /// - public ConnectorAttribute GetAttribute() - { - return _attribute; - } - - /// - /// Determines if the attribute provided is present in the - /// . - /// - public bool IsPresent(ConnectorObject obj) - { - return obj.GetAttributeByName(_attribute.Name) != null; - } - public abstract bool Accept(ConnectorObject obj); - } - #endregion - - #region ComparableAttributeFilter - /// - /// Filter for an attribute value that is comparable. - /// - public abstract class ComparableAttributeFilter : - SingleValueAttributeFilter - { - /// - /// Attempt compare attribute values. - /// - internal ComparableAttributeFilter(ConnectorAttribute attr) - : base(attr) - { - // determine if this attribute value is comparable.. - if (!(GetValue() is IComparable)) - { - String ERR = "Must be a comparable value!"; - throw new ArgumentException(ERR); - } - } - - /// - /// Call compareTo on the attribute values. - /// - /// - /// If the attribute is not present - /// in the return -1. - /// - public int Compare(ConnectorObject obj) - { - int ret = -1; - ConnectorAttribute attr = obj.GetAttributeByName(GetName()); - if (attr != null && attr.Value.Count == 1) - { - // it must be a comparable because that's were testing against - if (!(attr.Value[0] is IComparable)) - { - String ERR = "Attribute value must be comparable!"; - throw new ArgumentException(ERR); - } - // grab this value and the on from the attribute an compare.. - IComparable o1 = (IComparable)attr.Value[0]; - IComparable o2 = (IComparable)GetValue(); - ret = o1.CompareTo(o1); - } - return ret; - } - } - #endregion - - #region CompositeFilter - public abstract class CompositeFilter : Filter - { - public Filter Left { get; set; } - - public Filter Right { get; set; } - - internal CompositeFilter(Filter left, Filter right) - { - Left = left; - Right = right; - } - public abstract bool Accept(ConnectorObject obj); - } - #endregion - - #region ContainsFilter - public sealed class ContainsFilter : StringFilter - { - public ContainsFilter(ConnectorAttribute attr) - : base(attr) - { - } - - public override bool Accept(String value) - { - return value.Contains(GetValue()); - } - - public override string ToString() - { - StringBuilder bld = new StringBuilder(); - bld.Append("CONTAINS: ").Append(GetAttribute()); - return bld.ToString(); - } - } - #endregion - - #region EndsWithFilter - public sealed class EndsWithFilter : StringFilter - { - public EndsWithFilter(ConnectorAttribute attr) - : base(attr) - { - } - - public override bool Accept(String value) - { - return value.EndsWith(GetValue()); - } - - public override string ToString() - { - StringBuilder bld = new StringBuilder(); - bld.Append("ENDSWITH: ").Append(GetAttribute()); - return bld.ToString(); - } - } - #endregion - - #region EqualsFilter - public sealed class EqualsFilter : AttributeFilter - { - /// - /// Determines if the attribute inside the is equal - /// to the provided. - /// - public EqualsFilter(ConnectorAttribute attr) - : base(attr) - { - } - - /// - /// Determines if the attribute exists in the and if - /// its equal to the one provided. - /// - /// - public override bool Accept(ConnectorObject obj) - { - bool ret = false; - ConnectorAttribute thisAttr = GetAttribute(); - ConnectorAttribute attr = obj.GetAttributeByName(thisAttr.Name); - if (attr != null) - { - ret = thisAttr.Equals(attr); - } - return ret; - } - - public override string ToString() - { - StringBuilder bld = new StringBuilder(); - bld.Append("EQUALS: ").Append(GetAttribute()); - return bld.ToString(); - } - - } - #endregion - - #region Filter - public interface Filter - { - bool Accept(ConnectorObject obj); - } - #endregion - - #region FilterBuilder - /// - /// FilterBuilder creates a object, that can determine if a - /// ConnectorObject will be filtered or not. - /// - /// Will Droste - /// $Revision: 1.7 $ - /// 1.0 - public static class FilterBuilder - { - /// - /// Determine if the value ends - /// with the value provided. - /// - /// - /// value to test against the - /// attribute value. - /// true if the attribute value contains the - /// attribute value provided. - public static Filter EndsWith(ConnectorAttribute attr) - { - return new EndsWithFilter(attr); - } - - /// - /// Determine if the value starts - /// with the value provided. - /// - /// - /// value to test against the - /// attribute value. - /// true if the attribute value contains the - /// attribute value provided. - public static Filter StartsWith(ConnectorAttribute attr) - { - return new StartsWithFilter(attr); - } - - public static Filter ContainsAllValues(ConnectorAttribute attr) - { - return new ContainsAllValuesFilter(attr); - } - - /// - /// Determine if the value contains - /// the value provided. - /// - /// - /// value to test against the - /// attribute value. - /// true if the attribute value contains the - /// attribute value provided. - public static Filter Contains(ConnectorAttribute attr) - { - return new ContainsFilter(attr); - } - - /// - /// The value provided is less than or equal to the - /// attribute value. - /// - /// ConnectorAttribute to do the comparison. - /// true if attribute provided is greater than or equal to the one - /// provided by the . - public static Filter GreaterThanOrEqualTo(ConnectorAttribute attr) - { - return new GreaterThanOrEqualFilter(attr); - } - - /// - /// The value provided is less than or equal to the - /// attribute value. - /// - /// ConnectorAttribute to do the comparison. - /// true if attribute provided is less than or equal to the one - /// provided by the . - public static Filter LessThanOrEqualTo(ConnectorAttribute attr) - { - return new LessThanOrEqualFilter(attr); - } - - /// - /// The value provided is less than the - /// attribute value. - /// - /// ConnectorAttribute to do the comparison. - /// true if attribute provided is less than the one provided by the - /// . - public static Filter LessThan(ConnectorAttribute attr) - { - return new LessThanFilter(attr); - } - - /// - /// ConnectorAttribute value is greater than the attribute - /// value. - /// - /// ConnectorAttribute to do the comparison. - /// true if attribute provided is greater than the one provided by - /// the . - public static Filter GreaterThan(ConnectorAttribute attr) - { - return new GreaterThanFilter(attr); - } - - /// - /// Determines if the provided exists in the - /// and is equal. - /// - public static Filter EqualTo(ConnectorAttribute attr) - { - return new EqualsFilter(attr); - } - - /// - /// Ands the two . - /// - /// left side operand. - /// right side operand. - /// the result of leftOperand && rightOperand - public static Filter And(Filter leftOperand, Filter rightOperand) - { - return new AndFilter(leftOperand, rightOperand); - } - - /// - /// ORs the two . - /// - /// left side operand. - /// right side operand. - /// the result of leftOperand || rightOperand - public static Filter Or(Filter leftOperand, Filter rightOperand) - { - return new OrFilter(leftOperand, rightOperand); - } - - /// - /// NOT the . - /// - /// negate the result of . - /// the result of not . - public static Filter Not(Filter filter) - { - return new NotFilter(filter); - } - } - #endregion - - #region FilterTranslator - public interface FilterTranslator - { - IList Translate(Filter filter); - } - #endregion - - #region GreaterThanFilter - public sealed class GreaterThanFilter : ComparableAttributeFilter - { - /// - /// Determine if the value is - /// greater than the one provided in the filter. - /// - public GreaterThanFilter(ConnectorAttribute attr) - : base(attr) - { - } - - /// - /// Determine if the value is - /// greater than the one provided in the filter. - /// - /// - public override bool Accept(ConnectorObject obj) - { - return IsPresent(obj) && this.Compare(obj) > 0; - } - - public override string ToString() - { - StringBuilder bld = new StringBuilder(); - bld.Append("GREATERTHAN: ").Append(GetAttribute()); - return bld.ToString(); - } - } - #endregion - - #region GreaterThanOrEqualFilter - public sealed class GreaterThanOrEqualFilter : ComparableAttributeFilter - { - /// - /// Determine if the value is - /// greater than the one provided in the filter. - /// - public GreaterThanOrEqualFilter(ConnectorAttribute attr) - : base(attr) - { - } - - /// - /// Determine if the value is - /// greater than the one provided in the filter. - /// - /// - public override bool Accept(ConnectorObject obj) - { - return IsPresent(obj) && this.Compare(obj) >= 0; - } - - public override string ToString() - { - StringBuilder bld = new StringBuilder(); - bld.Append("GREATERTHANOREQUAL: ").Append(GetAttribute()); - return bld.ToString(); - } - } - #endregion - - #region LessThanFilter - public sealed class LessThanFilter : ComparableAttributeFilter - { - /// - /// Determine if the value is - /// greater than the one provided in the filter. - /// - public LessThanFilter(ConnectorAttribute attr) - : base(attr) - { - } - - /// - /// Determine if the value is - /// greater than the one provided in the filter. - /// - /// - public override bool Accept(ConnectorObject obj) - { - return IsPresent(obj) && this.Compare(obj) < 0; - } - - public override string ToString() - { - StringBuilder bld = new StringBuilder(); - bld.Append("LESSTHAN: ").Append(GetAttribute()); - return bld.ToString(); - } - } - #endregion - - #region LessThanOrEqualFilter - public sealed class LessThanOrEqualFilter : ComparableAttributeFilter - { - /// - /// Determine if the value is - /// greater than the one provided in the filter. - /// - public LessThanOrEqualFilter(ConnectorAttribute attr) - : base(attr) - { - } - - /// - /// Determine if the value is - /// greater than the one provided in the filter. - /// - /// - public override bool Accept(ConnectorObject obj) - { - return IsPresent(obj) && this.Compare(obj) <= 0; - } - - public override string ToString() - { - StringBuilder bld = new StringBuilder(); - bld.Append("LESSTHANOREQUAL: ").Append(GetAttribute()); - return bld.ToString(); - } - } - #endregion - - #region NotFilter - /// - /// Proxy the filter to return the negative of the value. - /// - public sealed class NotFilter : Filter - { - private readonly Filter _filter; - - /// - /// Take the value returned from the internal filter and NOT it. - /// - public NotFilter(Filter filter) - { - _filter = filter; - } - - /// - /// Get the internal filter that is being negated. - /// - public Filter Filter - { - get - { - return _filter; - } - } - - /// - /// Return the opposite the internal filters return value. - /// - /// - public bool Accept(ConnectorObject obj) - { - return !_filter.Accept(obj); - } - - public override string ToString() - { - StringBuilder bld = new StringBuilder(); - bld.Append("NOT: ").Append(Filter); - return bld.ToString(); - } - } - #endregion - - #region OrFilter - public sealed class OrFilter : CompositeFilter - { - /// - /// Or the left and right filters. - /// - public OrFilter(Filter left, Filter right) - : base(left, right) - { - } - - /// - /// ORs the left and right filters. - /// - /// - public override bool Accept(ConnectorObject obj) - { - return Left.Accept(obj) || Right.Accept(obj); - } - - public override string ToString() - { - StringBuilder bld = new StringBuilder(); - bld.Append("OR: ").Append(Left).Append(", ").Append(Right); - return bld.ToString(); - } - } - #endregion - - #region SingleValueAttributeFilter - /// - /// Get a single value out of the attribute to test w/. - /// - public abstract class SingleValueAttributeFilter : AttributeFilter - { - /// - /// Attempt to single out the value for comparison. - /// - internal SingleValueAttributeFilter(ConnectorAttribute attr) : - base(attr) - { - // make sure this is not a Uid.. - if (Uid.NAME.Equals(attr.Name)) - { - String MSG = "Uid can only be used for equals comparison."; - throw new ArgumentException(MSG); - } - // actual runtime.. - if (attr.Value.Count != 1) - { - String ERR = "Must only be one value!"; - throw new ArgumentException(ERR); - } - } - - /// - /// Value to test against. - /// - public Object GetValue() - { - return GetAttribute().Value[0]; - } - /// - /// Name of the attribute to find in the . - /// - public String GetName() - { - return GetAttribute().Name; - } - } - #endregion - - #region StartsWithFilter - public sealed class StartsWithFilter : StringFilter - { - public StartsWithFilter(ConnectorAttribute attr) - : base(attr) - { - } - - public override bool Accept(String value) - { - return value.StartsWith(GetValue()); - } - - public override string ToString() - { - StringBuilder bld = new StringBuilder(); - bld.Append("STARTSWITH: ").Append(GetAttribute()); - return bld.ToString(); - } - } - #endregion - - #region StringFilter - /// - /// Filter based on strings. - /// - public abstract class StringFilter : SingleValueAttributeFilter - { - /// - /// Attempts to get a string from the attribute. - /// - internal StringFilter(ConnectorAttribute attr) - : base(attr) - { - Object val = base.GetValue(); - if (!(val is string)) - { - String MSG = "Value must be a string!"; - throw new ArgumentException(MSG); - } - } - - /// - /// Get the string value from the afore mentioned attribute. - /// - /// - public new String GetValue() - { - return (String)base.GetValue(); - } - - /// - /// - /// iff the value from the 's attribute - /// of the same name as provided is not a string. - /// - public override bool Accept(ConnectorObject obj) - { - bool ret = false; - ConnectorAttribute attr = obj.GetAttributeByName(GetName()); - if (attr != null) - { - ret = Accept((string)attr.Value[0]); - } - return ret; - } - - public abstract bool Accept(String value); - } - #endregion - - #region ContainsAllValues Filter - public class ContainsAllValuesFilter : AttributeFilter - { - private readonly string _name; - private readonly ICollection _values; - - public ContainsAllValuesFilter(ConnectorAttribute attr) - : base(attr) - { - _name = attr.Name; - _values = attr.Value; - } - /// - /// Determine if the contains an - /// which contains all the values provided in the passed - /// into the filter. - /// - public override bool Accept(ConnectorObject obj) - { - bool rv = false; - ConnectorAttribute found = obj.GetAttributeByName(_name); - if (found != null) - { - // TODO: possible optimization using 'Set' - foreach (object o in _values) - { - if (!(rv = found.Value.Contains(o))) - { - break; - } - } - } - return rv; - } - } - #endregion -} \ No newline at end of file diff --git a/Framework/CommonSerializer.cs b/Framework/CommonSerializer.cs deleted file mode 100644 index 9524ba1..0000000 --- a/Framework/CommonSerializer.cs +++ /dev/null @@ -1,305 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.IO; -using System.Collections.Generic; -using Org.IdentityConnectors.Common; -namespace Org.IdentityConnectors.Framework.Common.Serializer -{ - /// - /// Interface for reading objects from a stream. - /// - public interface BinaryObjectDeserializer - { - /// - /// Reads the next object from the stream. - /// - /// - /// Throws - /// a wrapped if end of stream is reached. - /// - /// The next object from the stream. - object ReadObject(); - - /// - /// Closes the underlying stream - /// - void Close(); - } - /// - /// Interface for writing objects to a stream. - /// - public interface BinaryObjectSerializer - { - /// - /// Writes the next object to the stream. - /// - /// The object to write. - /// - void WriteObject(object obj); - - /// - /// Flushes the underlying stream. - /// - void Flush(); - - /// - /// Closes the underylying stream after first flushing it. - /// - void Close(); - } - - /// - /// Serializer factory for serializing connector objects. - /// - /// - /// The list of - /// supported types are as follows: - /// TODO: list supported types - /// - /// - /// - /// - public abstract class ObjectSerializerFactory - { - // At some point we might make this pluggable, but for now, hard-code - private const string IMPL_NAME = "Org.IdentityConnectors.Framework.Impl.Serializer.ObjectSerializerFactoryImpl"; - - private static ObjectSerializerFactory _instance; - - private static readonly Object LOCK = new Object(); - - - /// - /// Get the singleton instance of the . - /// - public static ObjectSerializerFactory GetInstance() - { - lock (LOCK) - { - if (_instance == null) - { - SafeType t = - FrameworkInternalBridge.LoadType(IMPL_NAME); - - _instance = t.CreateInstance(); - } - return _instance; - } - } - - /// - /// Creates a BinaryObjectSerializer for writing objects to - /// the given stream. - /// - /// - /// NOTE: consider using - /// for convenience serializing a single object. - /// - /// NOTE2: do not mix and match - /// with {. This is unsafe since there - /// is header information and state associated with the stream. Objects written - /// using one method must be read using the proper corresponding method. - /// - /// The stream - /// The serializer - public abstract BinaryObjectSerializer NewBinarySerializer(Stream os); - - /// - /// Creates a BinaryObjectDeserializer for reading objects from - /// the given stream. - /// - /// - /// NOTE: consider using - /// for convenience deserializing a single object. - /// NOTE2: do not mix and match - /// with {. This is unsafe since there - /// is header information and state associated with the stream. Objects written - /// using one method must be read using the proper corresponding method. - /// - /// The stream - /// The deserializer - public abstract BinaryObjectDeserializer NewBinaryDeserializer(Stream i); - - /// - /// Creates a BinaryObjectSerializer for writing objects to - /// the given stream. - /// - /// - /// NOTE: consider using - /// for convenience serializing a single object. - /// - /// NOTE2: do not mix and match - /// with {. - /// - /// The writer - /// True to include the xml header - /// Is this to produce a multi-object document. If false, only - /// a single object may be written. - /// The serializer - public abstract XmlObjectSerializer NewXmlSerializer(TextWriter w, - bool includeHeader, - bool multiObject); - - /// - /// Deserializes XML objects from a stream - /// NOTE: Consider using - /// for convenience deserializing a single object. - /// - /// - /// NOTE2: Do not mix and match - /// with {. - /// - /// The input source - /// The callback to receive objects from the stream - /// True iff we are to validate - public abstract void DeserializeXmlStream(TextReader reader, - XmlObjectResultsHandler handler, - bool validate); - - } - - /// - /// Bag of utilities for serialization - /// - public static class SerializerUtil - { - /// - /// Serializes the given object to bytes - /// - /// The object to serialize - /// The bytes - /// - public static byte[] SerializeBinaryObject(object obj) - { - ObjectSerializerFactory fact = ObjectSerializerFactory.GetInstance(); - MemoryStream mem = new MemoryStream(); - BinaryObjectSerializer ser = fact.NewBinarySerializer(mem); - ser.WriteObject(obj); - ser.Close(); - return mem.ToArray(); - } - - /// - /// Deserializes the given object from bytes - /// - /// The bytes to deserialize - /// The object - /// - public static object DeserializeBinaryObject(byte[] bytes) - { - ObjectSerializerFactory fact = ObjectSerializerFactory.GetInstance(); - MemoryStream mem = new MemoryStream(bytes); - BinaryObjectDeserializer des = fact.NewBinaryDeserializer(mem); - return des.ReadObject(); - } - - /// - /// Serializes the given object to xml - /// - /// The object to serialize - /// True if we are to include the xml header. - /// The xml - /// - public static String SerializeXmlObject(Object obj, bool includeHeader) - { - ObjectSerializerFactory fact = ObjectSerializerFactory.GetInstance(); - StringWriter w = new StringWriter(); - XmlObjectSerializer ser = fact.NewXmlSerializer(w, includeHeader, false); - ser.WriteObject(obj); - ser.Close(true); - return w.ToString(); - } - - /// - /// Deserializes the given object from xml - /// - /// The xml to deserialize - /// True if we are to validate the xml - /// The object - /// - public static Object DeserializeXmlObject(String str, bool validate) - { - ObjectSerializerFactory fact = ObjectSerializerFactory.GetInstance(); - StringReader source = new StringReader(str); - IList rv = new List(); - fact.DeserializeXmlStream(source, - obj => - { - rv.Add(obj); - return true; - }, validate); - if (rv.Count > 0) - { - return rv[0]; - } - else - { - return null; - } - } - - /// - /// Clones the given object by serializing it to bytes and then - /// deserializing it. - /// - /// The object. - /// A clone of the object - public static object CloneObject(Object obj) - { - byte[] bytes = SerializeBinaryObject(obj); - return DeserializeBinaryObject(bytes); - } - - } - - /// - /// Callback interface to receive xml objects from a stream of objects. - /// - public delegate bool XmlObjectResultsHandler(Object obj); - - /// - /// Interface for writing objects to a stream. - /// - public interface XmlObjectSerializer - { - /// - /// Writes the next object to the stream. - /// - /// The object to write. - /// - /// if there is more than one object - /// and this is not configured for multi-object document. - void WriteObject(Object obj); - - /// - /// Flushes the underlying stream. - /// - void Flush(); - - /// - /// Adds document end tag and optinally closes the underlying stream - /// - void Close(bool closeUnderlyingStream); - } -} \ No newline at end of file diff --git a/Framework/Framework.csproj b/Framework/Framework.csproj deleted file mode 100644 index 3a2e05f..0000000 --- a/Framework/Framework.csproj +++ /dev/null @@ -1,99 +0,0 @@ - - - - {8B24461B-456A-4032-89A1-CD418F7B5B62} - Debug - AnyCPU - Library - Org.IdentityConnectors.Framework - Framework - Open Connectors Framework - v3.5 - False - False - 4 - false - - - prompt - 4 - AnyCPU - bin\Debug\ - true - Full - False - True - DEBUG;TRACE - - - pdbonly - bin\Release\ - False - prompt - 4 - True - False - TRACE - - - False - Auto - 4194304 - AnyCPU - 4096 - - - - - - 3.5 - - - 3.5 - - - - - - - - - - - - - - - - - - {F140E8DA-52B4-4159-992A-9DA10EA8EEFB} - Common - - - - - - - diff --git a/Framework/Spi.cs b/Framework/Spi.cs deleted file mode 100644 index 55c8f95..0000000 --- a/Framework/Spi.cs +++ /dev/null @@ -1,340 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Globalization; -using System.Collections.Generic; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Common.Pooling; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Spi.Operations; -namespace Org.IdentityConnectors.Framework.Spi -{ - #region AttributeNormalizer - /// - /// Interface to be implemented by connectors that need - /// to normalize certain attributes. - /// - /// - /// This might, for - /// example, be used to normalize whitespace within - /// DN's to ensure consistent filtering whether that - /// filtering is natively on the resource or by the - /// connector framework. For connectors implementing - /// this interface, the method - /// will be applied to each of the following: - /// - /// - /// The filter passed to . - /// - /// - /// - /// The results returned from . - /// - /// - /// - /// The results returned from . - /// - /// - /// - /// The attributes passed to . - /// - /// - /// - /// The Uid returned from . - /// - /// - /// - /// The attributes passed to . - /// - /// - /// - /// The Uid returned from . - /// - /// - /// - /// The attributes passed to . - /// - /// - /// - /// The Uid returned from . - /// - /// - /// - /// The Uid passed to . - /// - /// - /// - /// - public interface AttributeNormalizer - { - ConnectorAttribute NormalizeAttribute(ObjectClass oclass, ConnectorAttribute attribute); - } - #endregion - - #region Configuration - /// - /// Encapsulates the configuration of a connector. - /// - /// Implementations of the Configuration interface must have a default - /// constructor. All properties are considered configuration for the connector. - /// The initial value of the property is - /// considered the default value of the property. The types of the properties - /// can be only those returned by and - /// multi-dimensional arrays thereof. The properties are not required by default, - /// but a property can be marked as required through use of the . - /// - /// - /// Each property corresponds to two entries in a resource named Messages: - /// [Property].display and [Property].help. For example, - /// hostname.help and hostname.display would be the keys - /// corresponding to a hostname property. The display message is the display - /// name of the property and can be used to display the property in a view. The help - /// message holds the description of the property. The names of the two keys can be overridden - /// through the ConfigurationProperty annotation. - /// - /// - public interface Configuration - { - /// - /// Gets or sets the {@link ConnectorMessages message catalog} instance that allows the Connector - /// to localize messages. The setter is called before any bean property setter, - /// the method or this property getter. - /// - ConnectorMessages ConnectorMessages { get; set; } - - /// - /// Determines if the configuration is valid. - /// - /// A valid configuration is one that is ready to be used by the connector: - /// it is complete (all the required properties have been given values) - /// and the property values are well-formed (are in the expected range, - /// have the expected format, etc.) - /// - /// - /// Implementations of this method should not connect to the resource - /// in an attempt to validate the configuration. For example, implementations - /// should not attempt to check that a host of the specified name exists - /// by making a connection to it. Such checks can be performed in the implementation - /// of the method. - /// - /// - /// iff the configuration is not valid. Implementations - /// are encouraged to throw the most specific exception available. - /// When no specific exception is available, implementations can throw - /// . - void Validate(); - } - #endregion - - #region AbstractConfiguration - public abstract class AbstractConfiguration : Configuration - { - - public ConnectorMessages ConnectorMessages { get; set; } - - public abstract void Validate(); - } - #endregion - - #region ConnectorClassAttribute - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] - public class ConnectorClassAttribute : System.Attribute - { - - private readonly String _connectorDisplayNameKey; - private readonly SafeType _connectorConfigurationClass; - - public ConnectorClassAttribute(String connectorDisplayNameKey, - Type connectorConfigurationClass) - { - _connectorDisplayNameKey = connectorDisplayNameKey; - _connectorConfigurationClass = SafeType.ForRawType(connectorConfigurationClass); - } - - public string ConnectorDisplayNameKey - { - get - { - return _connectorDisplayNameKey; - } - } - - public SafeType ConnectorConfigurationType - { - get - { - return _connectorConfigurationClass; - } - } - - public string[] MessageCatalogPaths { get; set; } - - } - #endregion - - #region ConfigurationPropertyAttribute - /// - /// The interface is traversed through reflection. This - /// annotation provides a way to override the default configuration operation for - /// each property. - /// - /// - /// - /// public class MyClass : Configuration { - /// [ConfigurationPropertionOptions(Confidential=true)] - /// public string MyProperty {get ; set;} - /// } - /// - /// - [AttributeUsage(AttributeTargets.Property)] - public class ConfigurationPropertyAttribute : System.Attribute - { - - /// - /// Order in which this property is displayed. - /// - public int Order { get; set; } - /// - /// Is this a confidential property whose value should be - /// encrypted by the application when persisted? - /// - public bool Confidential { get; set; } - /// - /// Is this a required property? - /// - public bool Required { get; set; } - /// - /// Change the default help message key. - /// - public string HelpMessageKey { get; set; } - /// - /// Change the default display message key. - /// - public string DisplayMessageKey { get; set; } - - /// - /// List of operations for which this property must be specified. - /// - /// - /// This is used for the case where a connector may or may not - /// implement certain operations depending in the configuration. - /// The default value of "empty array" is special in that - /// it means that this property is applicable to all operations. - /// MUST be SPI operations - /// - public Type[] OperationTypes { get; set; } - - /// - /// List of operations for which this property must be specified. - /// - /// - /// This is used for the case where a connector may or may not - /// implement certain operations depending in the configuration. - /// The default value of "empty array" is special in that - /// it means that this property is applicable to all operations. - /// - public SafeType[] Operations - { - get - { - Type[] types = OperationTypes; - SafeType[] rv = new SafeType[types.Length]; - for (int i = 0; i < types.Length; i++) - { - rv[i] = - SafeType.ForRawType(types[i]); - } - return rv; - } - } - - /// - /// Default constructor - /// - public ConfigurationPropertyAttribute() - { - Order = 1; - Confidential = false; - Required = false; - HelpMessageKey = null; - DisplayMessageKey = null; - OperationTypes = new Type[0]; - } - } - #endregion - - #region Connector - /// - /// This is the main interface to declare a connector. Developers must implement - /// this interface. The life-cycle for a is as follows - /// is called then any of the operations implemented - /// in the Connector and finally dispose. The and - /// allow for block operations. For instance bulk creates or - /// deletes and the use of before and after actions. Once is - /// called the object is discarded. - /// - public interface Connector : IDisposable - { - - /// - /// Initialize the connector with its configuration. For instance in a JDBC - /// Connector this would include the database URL, password, and user. - /// - /// instance of the object implemented by - /// the developer and populated with information - /// in order to initialize the . - void Init(Configuration configuration); - } - #endregion - - #region PoolableConnector - /// - /// To be implemented by Connectors that wish to be pooled. - /// - public interface PoolableConnector : Connector - { - /// - /// Checks if the connector is still alive. - /// - /// A connector can spend a large amount of time in the pool before - /// being used. This method is intended to check if the connector is - /// alive and operations can be invoked on it (for instance, an implementation - /// would check that the connector's physical connection to the resource - /// has not timed out). - /// - /// - /// The major difference between this method and is that - /// this method must do only the minimum that is necessary to check that the - /// connector is still alive. TestOp.Test() does a more thorough - /// check of the environment specified in the Configuration, and can therefore - /// be much slower. - /// - /// - /// This method can be called often. Implementations should do their - /// best to keep this method fast. - /// - /// if the connector is no longer alive. - void CheckAlive(); - } - #endregion -} \ No newline at end of file diff --git a/Framework/SpiOperations.cs b/Framework/SpiOperations.cs deleted file mode 100644 index 9698a3f..0000000 --- a/Framework/SpiOperations.cs +++ /dev/null @@ -1,492 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 Org.IdentityConnectors.Common.Security; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Common.Objects.Filters; - -namespace Org.IdentityConnectors.Framework.Spi.Operations -{ - /// - /// Authenticate an object based on their unique identifier and password. - /// - public interface AuthenticateOp : SPIOperation - { - /// - /// Simple authentication with two parameters presumed to be user name and - /// password. - /// - /// - /// The developer is expected to attempt to - /// authenticate these credentials natively. If the authentication fails the - /// developer should throw a type of either - /// or if a native exception is available - /// and if its of type simple throw it. If the - /// native exception is not a wrap it in one and - /// throw it. This will provide the most detail for logging problem and - /// failed attempts. - /// - /// The developer is of course encourage to try and throw the most - /// informative exception as possible. In that regards there are several - /// exceptions provided in the exceptions package. For instance one of the - /// most common is . - /// - /// - /// the name based credential for authentication. - /// the password based credential for authentication. - /// iff native authentication fails. If a native exception if - /// available attempt to throw it. - Uid Authenticate(ObjectClass objectClass, String username, GuardedString password, OperationOptions options); - } - - public interface ResolveUsernameOp : SPIOperation - { - /// - /// This is a companion to the simple with two parameters - /// presumed to be user name and password. - /// - /// - /// The difference is that this - /// method does not try to authenticate the credentials; instead, it - /// return the of the username that would be authenticated. - /// - /// If the authentication fails the - /// developer should throw a type of either - /// or if a native exception is available - /// and if its of type simple throw it. If the - /// native exception is not a wrap it in one and - /// throw it. This will provide the most detail for logging problem and - /// failed attempts. - /// - /// - /// The developer is of course encourage to try and throw the most - /// informative exception as possible. In that regards there are several - /// exceptions provided in the exceptions package. For instance one of the - /// most common is . - /// - /// - /// The object class to use for authenticate. - /// Will typically be an account. Will not be null. - /// the username that would be authenticated. Will not be null. - /// additional options that impact the way this operation is run. - /// If the caller passes null, the framework will convert this into - /// an empty set of options, so SPI need not worry - /// about this ever being null. - /// Uid The uid of the account that would be authenticated. - /// iff native authentication fails. If a native exception is - /// available attempt to throw it. - Uid ResolveUsername(ObjectClass objectClass, String username, OperationOptions options); - } - - /// - /// The developer is responsible for taking the attributes - /// given (which always includes the ) and create an object - /// and its . - /// - /// - /// The developer must return the - /// so that the caller can refer to the created object. - /// - /// The developer should make a best effort to create the - /// object otherwise throw an informative telling the - /// caller why the operation could not be completed. It reasonable to use - /// defaults for required s as long as they are documented. - /// - /// - /// Will Droste - /// $Revision $ - /// 1.0 - public interface CreateOp : SPIOperation - { - /// - /// The developer is responsible for taking the attributes - /// given (which always includes the ) and create an - /// object and its . - /// - /// - /// The developer must return - /// the so that the caller can refer to the created object. - /// - /// specifies the name of the object to create. - /// includes all the attributes necessary to create the resource - /// object including the attribute. - /// the unique id for the object that is created. For instance in - /// LDAP this would be the 'dn', for a database this would be the - /// primary key, and for 'ActiveDirectory' this would be the GUID. - Uid Create(ObjectClass oclass, ICollection attrs, OperationOptions options); - } - - /// - /// Deletes an object with the specified Uid and ObjectClass on the - /// resource. - /// - public interface DeleteOp : SPIOperation - { - /// - /// Delete the object that the specified Uid identifies (if any). - /// - /// The type of object to delete. - /// The unique identitfier for the object to delete. - /// Throws UnknowUid if the object does not exist. - void Delete(ObjectClass objClass, Uid uid, OperationOptions options); - } - - public interface SchemaOp : SPIOperation - { - /// - /// Determines what types of objects this supports. - /// - /// - /// This - /// method is considered an operation since determining supported objects may - /// require configuration information and allows this determination to be - /// dynamic. - /// - /// basic schema supported by this . - Schema Schema(); - } - /// - /// Operation that runs a script in the environment of the connector. - /// - /// - /// (Compare to , which runs a script - /// on the target resource that the connector manages.) - /// A connector that intends to provide to scripts - /// more than is required by the basic contract - /// specified in the javadoc for - /// should implement this interface. - /// - /// Each connector that implements this interface must support - /// at least the behavior specified by . - /// A connector also may expose additional variables for use by scripts - /// and may respond to specific . - /// Each connector that implements this interface - /// must describe in its javadoc as available "for use by connector scripts" - /// any such additional variables or supported options. - /// - /// - public interface ScriptOnConnectorOp : SPIOperation - { - - /// - /// Runs the script request. - /// - /// The script and arguments to run. - /// Additional options that control how the script is - /// run. - /// The result of the script. The return type must be - /// a type that the framework supports for serialization. - /// See for a list of supported types. - Object RunScriptOnConnector(ScriptContext request, - OperationOptions options); - } - /// - /// Operation that runs a script directly on a target resource. - /// - /// - /// (Compare to , which runs a script - /// in the context of a particular connector.) - /// - /// A connector that intends to support - /// - /// should implement this interface. Each connector that implements - /// this interface must document which script languages the connector supports, - /// as well as any supported . - /// - /// - public interface ScriptOnResourceOp : SPIOperation - { - /// - /// Run the specified script on the target resource - /// that this connector manages. - /// - /// The script and arguments to run. - /// Additional options that control - /// how the script is run. - /// The result of the script. The return type must be - /// a type that the framework supports for serialization. - /// See for a list of supported types. - Object RunScriptOnResource(ScriptContext request, - OperationOptions options); - } - - /// - /// Implement this interface to allow the Connector to search for resource - /// objects. - /// - public interface SearchOp : SPIOperation where T : class - { - /// - /// Creates a filter translator that will translate - /// a specified filter to the native filter. - /// - /// - /// The - /// translated filters will be subsequently passed to - /// - /// - /// The object class for the search. Will never be null. - /// additional options that impact the way this operation is run. - /// If the caller passes null, the framework will convert this into - /// an empty set of options, so SPI need not worry - /// about this ever being null. - /// A filter translator. - FilterTranslator CreateFilterTranslator(ObjectClass oclass, OperationOptions options); - /// - /// This will be called by ConnectorFacade, once for each native query produced - /// by the FilterTranslator. - /// - /// - /// If there is more than one query the results will - /// automatically be merged together and duplicates eliminated. NOTE - /// that this implies an in-memory data structure that holds a set of - /// Uids, so memory usage in the event of multiple queries will be O(N) - /// where N is the number of results. That is why it is important that - /// the FilterTranslator implement OR if possible. - /// - /// The object class for the search. Will never be null. - /// The native query to run. A value of null means 'return everything for the given object class'. - /// Results should be returned to this handler - /// additional options that impact the way this operation is run. - /// If the caller passes null, the framework will convert this into - /// an empty set of options, so SPI need not worry - /// about this ever being null. - void ExecuteQuery(ObjectClass oclass, T query, ResultsHandler handler, OperationOptions options); - } - /// - /// Receive synchronization events from the resource. - /// - /// - public interface SyncOp : SPIOperation - { - /// - /// Perform a synchronization. - /// - /// The object class to synchronize. Must not be null. - /// The token representing the last token from the previous sync. - /// Should be null if this is the first sync for the given - /// resource. - /// The result handler Must not be null. - /// additional options that impact the way this operation is run. - /// If the caller passes null, the framework will convert this into - /// an empty set of options, so SPI need not worry - /// about this ever being null. - void Sync(ObjectClass objClass, SyncToken token, - SyncResultsHandler handler, - OperationOptions options); - /// - /// Returns the token corresponding to the latest sync delta. - /// - /// - /// This is to support applications that may wish to sync starting - /// "now". - /// - /// The latest token or null if there is no sync data. - SyncToken GetLatestSyncToken(ObjectClass objectClass); - } - - /// - /// The developer of a Connector should implement either this interface or the - /// interface if the Connector will allow an authorized - /// caller to update (i.e., modify or replace) objects on the target resource. - /// - /// - /// - /// This update method is simpler to implement than {link UpdateAttributeValuesOp}, - /// which must handle any of several different types of update that the caller - /// may specify. However a true implementation of {link UpdateAttributeValuesOp} - /// offers better performance and atomicity semantics. - /// - /// - /// Will Droste - /// $Revision $ - /// 1.0 - public interface UpdateOp : SPIOperation - { - /// - /// Update the object specified by the and , - /// replacing the current values of each attribute with the values - /// provided. - /// - /// - /// - /// For each input attribute, replace - /// all of the current values of that attribute in the target object with - /// the values of that attribute. - /// - /// - /// If the target object does not currently contain an attribute that the - /// input set contains, then add this - /// attribute (along with the provided values) to the target object. - /// - /// - /// If the value of an attribute in the input set is - /// null, then do one of the following, depending on - /// which is most appropriate for the target: - /// - /// - /// If possible, remove that attribute from the target - /// object entirely. - /// - /// - /// - /// Otherwise, replace all of the current values of that - /// attribute in the target object with a single value of - /// null. - /// - /// - /// - /// - /// - /// the type of object to modify. Will never be null. - /// the uid of the object to modify. Will never be null. - /// set of new . the values in this set - /// represent the new, merged values to be applied to the object. - /// This set may also include . - /// Will never be null. - /// additional options that impact the way this operation is run. - /// Will never be null. - /// the of the updated object in case the update changes - /// the formation of the unique identifier. - /// iff the does not exist on the resource. - Uid Update(ObjectClass objclass, - Uid uid, - ICollection replaceAttributes, - OperationOptions options); - } - - /// - /// More advanced implementation of to be implemented by - /// connectors that wish to offer better performance and atomicity semantics - /// for the methods - /// and . - /// - public interface UpdateAttributeValuesOp : UpdateOp - { - - /// - /// Update the object specified by the and , - /// adding to the current values of each attribute the values provided. - /// - /// - /// - /// For each attribute that the input set contains, add to - /// the current values of that attribute in the target object all of the - /// values of that attribute in the input set. - /// - /// - /// NOTE that this does not specify how to handle duplicate values. - /// The general assumption for an attribute of a ConnectorObject - /// is that the values for an attribute may contain duplicates. - /// Therefore, in general simply append the provided values - /// to the current value for each attribute. - /// - /// - /// - /// - /// the type of object to modify. Will never be null. - /// the uid of the object to modify. Will never be null. - /// set of deltas. The values for the attributes - /// in this set represent the values to add to attributes in the object. - /// merged. This set will never include . - /// Will never be null. - /// additional options that impact the way this operation is run. - /// Will never be null. - /// the of the updated object in case the update changes - /// the formation of the unique identifier. - /// iff the does not exist on the resource. - Uid AddAttributeValues(ObjectClass objclass, - Uid uid, - ICollection valuesToAdd, - OperationOptions options); - - /// - /// Update the object specified by the and , - /// removing from the current values of each attribute the values provided. - /// - /// - /// - /// For each attribute that the input set contains, - /// remove from the current values of that attribute in the target object - /// any value that matches one of the values of the attribute from the input set. - /// - /// - /// NOTE that this does not specify how to handle unmatched values. - /// The general assumption for an attribute of a ConnectorObject - /// is that the values for an attribute are merely representational state. - /// Therefore, the implementer should simply ignore any provided value - /// that does not match a current value of that attribute in the target - /// object. Deleting an unmatched value should always succeed. - /// - /// - /// the type of object to modify. Will never be null. - /// the uid of the object to modify. Will never be null. - /// set of deltas. The values for the attributes - /// in this set represent the values to remove from attributes in the object. - /// merged. This set will never include . - /// Will never be null. - /// additional options that impact the way this operation is run. - /// Will never be null.. - /// the of the updated object in case the update changes - /// the formation of the unique identifier. - /// iff the does not exist on the resource. - Uid RemoveAttributeValues(ObjectClass objclass, - Uid uid, - ICollection valuesToRemove, - OperationOptions options); - } - - /// - /// Tests the connector . - /// - /// Unlike validation performed by , testing a configuration - /// checks that any pieces of environment referred by the configuration are available. - /// For example, the connector could make a physical connection to a host specified - /// in the configuration to check that it exists and that the credentials - /// specified in the configuration are usable. - /// - /// - /// This operation may be invoked before the configuration has been validated. - /// An implementation is free to validate the configuration before testing it. - /// - public interface TestOp : SPIOperation - { - /// - /// Tests the with the connector. - /// - /// iff the configuration is not valid or the test failed. Implementations - /// are encouraged to throw the most specific exception available. - /// When no specific exception is available, implementations can throw - /// . - void Test(); - } - - /// - /// Tagging interface for the SPI. - /// - public interface SPIOperation - { - } -} \ No newline at end of file diff --git a/Framework/version.template b/Framework/version.template deleted file mode 100644 index db70057..0000000 --- a/Framework/version.template +++ /dev/null @@ -1 +0,0 @@ -1.2.0.0 diff --git a/FrameworkInternal/Api.cs b/FrameworkInternal/Api.cs deleted file mode 100644 index 4334a57..0000000 --- a/FrameworkInternal/Api.cs +++ /dev/null @@ -1,988 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 Org.IdentityConnectors.Framework.Api; -using Org.IdentityConnectors.Framework.Api.Operations; -using Org.IdentityConnectors.Framework.Common; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Common.Objects.Filters; -using Org.IdentityConnectors.Framework.Common.Serializer; -using Org.IdentityConnectors.Framework.Impl.Api.Local; -using Org.IdentityConnectors.Framework.Impl.Api.Remote; -using Org.IdentityConnectors.Framework.Impl.Serializer.Binary; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Common.Pooling; -using Org.IdentityConnectors.Common.Proxy; -using Org.IdentityConnectors.Common.Security; -using System.Linq; -using System.Collections.Generic; -using System.Globalization; -using System.Resources; -using System.Reflection; -using System.Reflection.Emit; -using System.Diagnostics; -using System.Text; - -namespace Org.IdentityConnectors.Framework.Impl.Api -{ - #region ConfigurationPropertyImpl - /// - /// Internal class, public only for unit tests - /// - public class ConfigurationPropertyImpl : ConfigurationProperty - { - private ICollection> _operations; - - public ICollection> Operations - { - get - { - return _operations; - } - set - { - _operations = CollectionUtil.NewReadOnlySet(value); - } - } - - public ConfigurationPropertiesImpl Parent { get; set; } - - public int Order { get; set; } - - public string Name { get; set; } - - public string HelpMessageKey { get; set; } - - public string DisplayMessageKey { get; set; } - - public string GetHelpMessage(string def) - { - return FormatMessage(HelpMessageKey, def); - } - - public string GetDisplayName(string def) - { - return FormatMessage(DisplayMessageKey, def); - } - - public object Value { get; set; } - - public Type ValueType { get; set; } - - public bool IsConfidential { get; set; } - - public bool IsRequired { get; set; } - - public override int GetHashCode() - { - return Name.GetHashCode(); - } - - public override bool Equals(Object o) - { - ConfigurationPropertyImpl other = o as ConfigurationPropertyImpl; - if (other != null) - { - if (!Name.Equals(other.Name)) - { - return false; - } - if (!CollectionUtil.Equals(Value, other.Value)) - { - return false; - } - if (Order != other.Order) - { - return false; - } - if (!CollectionUtil.Equals(HelpMessageKey, other.HelpMessageKey)) - { - return false; - } - if (!CollectionUtil.Equals(DisplayMessageKey, other.DisplayMessageKey)) - { - return false; - } - if (IsConfidential != other.IsConfidential) - { - return false; - } - if (IsRequired != other.IsRequired) - { - return false; - } - if (!CollectionUtil.Equals(ValueType, other.ValueType)) - { - return false; - } - if (!CollectionUtil.Equals(_operations, other._operations)) - { - return false; - } - - return true; - } - return false; - } - private String FormatMessage(String key, String dflt, params object[] args) - { - APIConfigurationImpl apiConfig = Parent.Parent; - ConnectorMessages messages = - apiConfig.ConnectorInfo.Messages; - return messages.Format(key, dflt, args); - } - } - #endregion - - #region ConfigurationPropertiesImpl - /// - /// Internal class, public only for unit tests - /// - public class ConfigurationPropertiesImpl : ConfigurationProperties - { - //properties, sorted by "order" - private IList _properties; - //property names, sorted by "order - private IList _propertyNames; - private IDictionary _propertiesByName; - - public IList Properties - { - get - { - return _properties; - } - set - { - ConfigurationPropertyImpl[] arr = - value == null ? new ConfigurationPropertyImpl[0] : value.ToArray(); - - Array.Sort(arr, - (p1, p2) => { return p1.Order.CompareTo(p2.Order); }); - _properties = - CollectionUtil.NewReadOnlyList(arr); - IList propertyNames = new List(); - IDictionary propertiesByName = - new Dictionary(); - foreach (ConfigurationPropertyImpl property in _properties) - { - propertyNames.Add(property.Name); - propertiesByName[property.Name] = property; - property.Parent = this; - } - _propertyNames = CollectionUtil.AsReadOnlyList(propertyNames); - _propertiesByName = CollectionUtil.AsReadOnlyDictionary(propertiesByName); - } - } - public ConfigurationProperty GetProperty(String name) - { - return CollectionUtil.GetValue(_propertiesByName, name, null); - } - public IList PropertyNames - { - get - { - return _propertyNames; - } - } - public APIConfigurationImpl Parent { get; set; } - public void SetPropertyValue(String name, object val) - { - ConfigurationProperty property = GetProperty(name); - if (property == null) - { - String MSG = "Property '" + name + "' does not exist."; - throw new ArgumentException(MSG); - } - property.Value = val; - } - - public override int GetHashCode() - { - return CollectionUtil.GetHashCode(_properties); - } - - public override bool Equals(object o) - { - ConfigurationPropertiesImpl other = o as ConfigurationPropertiesImpl; - if (other != null) - { - return CollectionUtil.SetsEqual(_properties, - other._properties); - } - return false; - } - } - #endregion - - #region APIConfigurationImpl - /// - /// Internal class, public only for unit tests - /// - public class APIConfigurationImpl : APIConfiguration - { - private ObjectPoolConfiguration _connectorPooling; - - private ConfigurationPropertiesImpl _configurationProperties; - private ICollection> _supportedOperations = - CollectionUtil.NewReadOnlySet>(new SafeType[0]); - - private IDictionary, int> _timeoutMap = - new Dictionary, int>(); - - public ConfigurationProperties ConfigurationProperties - { - get - { - return _configurationProperties; - } - set - { - if (_configurationProperties != null) - { - _configurationProperties.Parent = null; - } - _configurationProperties = (ConfigurationPropertiesImpl)value; - if (_configurationProperties != null) - { - _configurationProperties.Parent = this; - } - } - } - public IDictionary, int> TimeoutMap - { - get - { - return _timeoutMap; - } - set - { - _timeoutMap = value; - } - } - public bool IsConnectorPoolingSupported { get; set; } - public ObjectPoolConfiguration ConnectorPoolConfiguration - { - get - { - if (_connectorPooling == null) - { - _connectorPooling = new ObjectPoolConfiguration(); - } - return _connectorPooling; - } - set - { - _connectorPooling = value; - } - } - public ICollection> SupportedOperations - { - get - { - return _supportedOperations; - } - set - { - _supportedOperations = CollectionUtil.NewReadOnlySet>(value); - } - } - - public int GetTimeout(SafeType operation) - { - return CollectionUtil.GetValue(_timeoutMap, operation, - APIConstants.NO_TIMEOUT); - } - public void SetTimeout(SafeType operation, int timeout) - { - _timeoutMap[operation] = timeout; - } - - public AbstractConnectorInfo ConnectorInfo { get; set; } - - public int ProducerBufferSize { get; set; } - public APIConfigurationImpl() - { - ProducerBufferSize = 100; - } - } - #endregion - - #region AbstractConnectorInfo - /// - /// internal class, public only for unit tests - /// - public class AbstractConnectorInfo : ConnectorInfo - { - private APIConfigurationImpl _defaultAPIConfiguration; - - - public string GetConnectorDisplayName() - { - return Messages.Format(ConnectorDisplayNameKey, - ConnectorKey.ConnectorName); - } - - public ConnectorKey ConnectorKey { get; set; } - - public string ConnectorDisplayNameKey { get; set; } - - public ConnectorMessages Messages { get; set; } - - public APIConfigurationImpl DefaultAPIConfiguration - { - get - { - return _defaultAPIConfiguration; - } - set - { - if (value != null) - { - value.ConnectorInfo = this; - } - _defaultAPIConfiguration = value; - } - } - - public APIConfiguration CreateDefaultAPIConfiguration() - { - APIConfigurationImpl rv = - (APIConfigurationImpl) - SerializerUtil.CloneObject(_defaultAPIConfiguration); - rv.ConnectorInfo = this; - return rv; - } - } - #endregion - - #region ConnectorMessagesImpl - /// - /// internal class, public only for unit tests - /// - public class ConnectorMessagesImpl : ConnectorMessages - { - private IDictionary> - _catalogs = new Dictionary>(); - - public String Format(String key, String dflt, params object[] args) - { - if (key == null) - { - return dflt; - } - CultureInfo locale = CultureInfo.CurrentUICulture; - if (locale == null) - { - locale = CultureInfo.CurrentCulture; - } - if (dflt == null) - { - dflt = key; - } - CultureInfo foundCulture = locale; - String message = GetCatalogMessage(foundCulture, key); - //check neutral culture - if (message == null) - { - foundCulture = foundCulture.Parent; - message = GetCatalogMessage(foundCulture, key); - } - //check invariant culture - if (message == null) - { - foundCulture = foundCulture.Parent; - message = GetCatalogMessage(foundCulture, key); - } - //and default to framework - if (message == null) - { - message = GetFrameworkMessage(locale, key); - } - if (message == null) - { - return dflt; - } - else - { - //TODO: think more about this since the formatting - //is slightly different than Java - return String.Format(foundCulture, message, args); - } - } - - private String GetCatalogMessage(CultureInfo culture, String key) - { - IDictionary catalog = CollectionUtil.GetValue(_catalogs, culture, null); - return catalog != null ? CollectionUtil.GetValue(catalog, key, null) : null; - } - - private String GetFrameworkMessage(CultureInfo culture, String key) - { - ResourceManager manager = - new ResourceManager("Org.IdentityConnectors.Resources", - typeof(ConnectorMessagesImpl).Assembly); - String contents = (String)manager.GetObject(key, culture); - return contents; - } - - public IDictionary> Catalogs - { - get - { - return _catalogs; - } - set - { - if (value == null) - { - _catalogs = - new Dictionary>(); - } - else - { - _catalogs = value; - } - } - } - } - #endregion - - #region ConnectorInfoManagerFactoryImpl - public sealed class ConnectorInfoManagerFactoryImpl : - ConnectorInfoManagerFactory - { - private class RemoteManagerKey - { - private readonly String _host; - private readonly int _port; - - public RemoteManagerKey(RemoteFrameworkConnectionInfo info) - { - _host = info.Host; - _port = info.Port; - } - - public override bool Equals(Object o) - { - if (o is RemoteManagerKey) - { - RemoteManagerKey other = (RemoteManagerKey)o; - if (!_host.Equals(other._host)) - { - return false; - } - if (_port != other._port) - { - return false; - } - return true; - } - return false; - } - - public override int GetHashCode() - { - return _host.GetHashCode() ^ _port; - } - - } - - private Object LOCAL_LOCK = new Object(); - private Object REMOTE_LOCK = new Object(); - - private ConnectorInfoManager - _localManagerCache; - - private IDictionary - _remoteManagerCache = new Dictionary(); - - public ConnectorInfoManagerFactoryImpl() - { - - } - - public override void ClearRemoteCache() - { - lock (REMOTE_LOCK) - { - _remoteManagerCache.Clear(); - } - } - - public override ConnectorInfoManager GetLocalManager() - { - lock (LOCAL_LOCK) - { - ConnectorInfoManager rv = _localManagerCache; - if (rv == null) - { - rv = new LocalConnectorInfoManagerImpl(); - } - _localManagerCache = rv; - return rv; - } - } - - public override ConnectorInfoManager GetRemoteManager(RemoteFrameworkConnectionInfo info) - { - RemoteManagerKey key = new RemoteManagerKey(info); - lock (REMOTE_LOCK) - { - RemoteConnectorInfoManagerImpl rv = CollectionUtil.GetValue(_remoteManagerCache, key, null); - if (rv == null) - { - rv = new RemoteConnectorInfoManagerImpl(info); - } - _remoteManagerCache[key] = rv; - return rv.Derive(info); - } - } - - } - #endregion - - #region AbstractConnectorFacade - internal abstract class AbstractConnectorFacade : ConnectorFacade - { - private readonly APIConfigurationImpl _configuration; - - /// - /// Builds up the maps of supported operations and calls. - /// - public AbstractConnectorFacade(APIConfigurationImpl configuration) - { - Assertions.NullCheck(configuration, "configuration"); - //clone in case application tries to modify - //after the fact. this is necessary to - //ensure thread-safety of a ConnectorFacade - //also, configuration is used as a key in the - //pool, so it is important that it not be modified. - _configuration = (APIConfigurationImpl)SerializerUtil.CloneObject(configuration); - //parent ref not included in the clone - _configuration.ConnectorInfo = (configuration.ConnectorInfo); - } - - /// - /// Return an instance of an API operation. - /// - /// - /// null if the operation is not support otherwise - /// return an instance of the operation. - /// - public APIOperation GetOperation(SafeType api) - { - if (!SupportedOperations.Contains(api)) - { - return null; - } - return GetOperationImplementation(api); - } - - public ICollection> SupportedOperations - { - get - { - return _configuration.SupportedOperations; - } - } - - // ======================================================================= - // Operation API Methods - // ======================================================================= - public Schema Schema() - { - return ((SchemaApiOp)this.GetOperationCheckSupported(SafeType.Get())) - .Schema(); - } - - public Uid Create(ObjectClass oclass, ICollection attrs, OperationOptions options) - { - CreateApiOp op = ((CreateApiOp)GetOperationCheckSupported(SafeType.Get())); - return op.Create(oclass, attrs, options); - } - - public void Delete(ObjectClass objClass, Uid uid, OperationOptions options) - { - ((DeleteApiOp) - this.GetOperationCheckSupported(SafeType.Get())) - .Delete(objClass, uid, options); - } - - public void Search(ObjectClass oclass, Filter filter, ResultsHandler handler, OperationOptions options) - { - ((SearchApiOp)this.GetOperationCheckSupported(SafeType.Get())).Search( - oclass, filter, handler, options); - } - - public Uid Update(ObjectClass objclass, Uid uid, ICollection attrs, OperationOptions options) - { - return ((UpdateApiOp)this.GetOperationCheckSupported(SafeType.Get())) - .Update(objclass, uid, attrs, options); - } - - public Uid AddAttributeValues( - ObjectClass objclass, - Uid uid, - ICollection attrs, - OperationOptions options) - { - return ((UpdateApiOp)this.GetOperationCheckSupported(SafeType.Get())) - .AddAttributeValues(objclass, uid, attrs, options); - } - - public Uid RemoveAttributeValues( - ObjectClass objclass, - Uid uid, - ICollection attrs, - OperationOptions options) - { - return ((UpdateApiOp)this.GetOperationCheckSupported(SafeType.Get())) - .RemoveAttributeValues(objclass, uid, attrs, options); - } - - public Uid Authenticate(ObjectClass objectClass, String username, GuardedString password, OperationOptions options) - { - return ((AuthenticationApiOp)this - .GetOperationCheckSupported(SafeType.Get())).Authenticate( - objectClass, username, password, options); - } - - public Uid ResolveUsername(ObjectClass objectClass, String username, OperationOptions options) - { - return ((ResolveUsernameApiOp)this - .GetOperationCheckSupported(SafeType.Get())).ResolveUsername( - objectClass, username, options); - } - - public ConnectorObject GetObject(ObjectClass objClass, Uid uid, OperationOptions options) - { - return ((GetApiOp)this.GetOperationCheckSupported(SafeType.Get())) - .GetObject(objClass, uid, options); - } - - public Object RunScriptOnConnector(ScriptContext request, - OperationOptions options) - { - return ((ScriptOnConnectorApiOp)this - .GetOperationCheckSupported(SafeType.Get())) - .RunScriptOnConnector(request, options); - } - - public Object RunScriptOnResource(ScriptContext request, - OperationOptions options) - { - return ((ScriptOnResourceApiOp)this - .GetOperationCheckSupported(SafeType.Get())) - .RunScriptOnResource(request, options); - } - - public void Test() - { - ((TestApiOp)this.GetOperationCheckSupported(SafeType.Get())).Test(); - } - - public void Validate() - { - ((ValidateApiOp)this.GetOperationCheckSupported(SafeType.Get())).Validate(); - } - - public void Sync(ObjectClass objClass, SyncToken token, - SyncResultsHandler handler, - OperationOptions options) - { - ((SyncApiOp)this.GetOperationCheckSupported(SafeType.Get())) - .Sync(objClass, token, handler, options); - } - - public SyncToken GetLatestSyncToken(ObjectClass objectClass) - { - return ((SyncApiOp)this.GetOperationCheckSupported(SafeType.Get())) - .GetLatestSyncToken(objectClass); - } - - private APIOperation GetOperationCheckSupported(SafeType api) - { - // check if this operation is supported. - if (!SupportedOperations.Contains(api)) - { - String MSG = "Operation ''{0}'' not supported."; - String str = String.Format(MSG, api); - throw new InvalidOperationException(str); - } - return GetOperationImplementation(api); - } - - /// - /// Gets the implementation of the given operation - /// - /// The operation to implement. - /// The implementation - protected abstract APIOperation GetOperationImplementation(SafeType api); - - protected APIConfigurationImpl GetAPIConfiguration() - { - return _configuration; - } - - /// - /// Creates a new proxy given a handler. - /// - protected APIOperation NewAPIOperationProxy(SafeType api, InvocationHandler handler) - { - return (APIOperation)Proxy.NewProxyInstance(api.RawType, handler); - } - - private static bool LOGGINGPROXY_ENABLED; - static AbstractConnectorFacade() - { - string enabled = System.Configuration. - ConfigurationManager.AppSettings.Get("logging.proxy"); - LOGGINGPROXY_ENABLED = StringUtil.IsTrue(enabled); - } - - protected APIOperation CreateLoggingProxy(SafeType api, APIOperation target) - { - APIOperation ret = target; - if (LOGGINGPROXY_ENABLED) - { - LoggingProxy logging = new LoggingProxy(api, target); - ret = NewAPIOperationProxy(api, logging); - } - return ret; - } - } - #endregion - - #region ConnectorFacadeFactoryImpl - public class ConnectorFacadeFactoryImpl : ConnectorFacadeFactory - { - public override ConnectorFacade NewInstance(APIConfiguration config) - { - ConnectorFacade ret = null; - APIConfigurationImpl impl = (APIConfigurationImpl)config; - AbstractConnectorInfo connectorInfo = impl.ConnectorInfo; - if (connectorInfo is LocalConnectorInfoImpl) - { - LocalConnectorInfoImpl localInfo = - (LocalConnectorInfoImpl)connectorInfo; - // create a new Provisioner.. - ret = new LocalConnectorFacadeImpl(localInfo, impl); - } - else - { - ret = new RemoteConnectorFacadeImpl(impl); - } - return ret; - } - - - /// - /// Dispose of all object pools and other resources associated with this - /// class. - /// - public override void Dispose() - { - ConnectorPoolManager.Dispose(); - } - - } - #endregion - - #region ObjectStreamHandler - internal interface ObjectStreamHandler - { - bool Handle(Object obj); - } - #endregion - - #region StreamHandlerUtil - internal static class StreamHandlerUtil - { - /// - /// Adapts from a ObjectStreamHandler to a ResultsHandler - /// - private class ResultsHandlerAdapter - { - private readonly ObjectStreamHandler _target; - public ResultsHandlerAdapter(ObjectStreamHandler target) - { - _target = target; - } - public bool Handle(ConnectorObject obj) - { - return _target.Handle(obj); - } - } - - /// - /// Adapts from a ObjectStreamHandler to a SyncResultsHandler - /// - private class SyncResultsHandlerAdapter - { - private readonly ObjectStreamHandler _target; - public SyncResultsHandlerAdapter(ObjectStreamHandler target) - { - _target = target; - } - public bool Handle(SyncDelta obj) - { - return _target.Handle(obj); - } - } - - /// - /// Adapts from a ObjectStreamHandler to a SyncResultsHandler - /// - private class ObjectStreamHandlerAdapter : ObjectStreamHandler - { - private readonly Type _targetInterface; - private readonly Object _target; - public ObjectStreamHandlerAdapter(Type targetInterface, Object target) - { - Assertions.NullCheck(targetInterface, "targetInterface"); - Assertions.NullCheck(target, "target"); - if (!targetInterface.IsAssignableFrom(target.GetType())) - { - throw new ArgumentException("Target" + targetInterface + " " + target); - } - if (!IsAdaptableToObjectStreamHandler(targetInterface)) - { - throw new ArgumentException("Target interface not supported: " + targetInterface); - } - _targetInterface = targetInterface; - _target = target; - } - public bool Handle(Object obj) - { - if (_targetInterface.Equals(typeof(ResultsHandler))) - { - return ((ResultsHandler)_target)((ConnectorObject)obj); - } - else if (_targetInterface.Equals(typeof(SyncResultsHandler))) - { - return ((SyncResultsHandler)_target)((SyncDelta)obj); - } - else - { - throw new InvalidOperationException("Unhandled case: " + _targetInterface); - } - } - } - - public static bool IsAdaptableToObjectStreamHandler(Type clazz) - { - return (typeof(ResultsHandler).IsAssignableFrom(clazz) || - typeof(SyncResultsHandler).IsAssignableFrom(clazz)); - } - - public static ObjectStreamHandler AdaptToObjectStreamHandler(Type interfaceType, - Object target) - { - return new ObjectStreamHandlerAdapter(interfaceType, target); - } - public static Object AdaptFromObjectStreamHandler(Type interfaceType, - ObjectStreamHandler target) - { - if (interfaceType.Equals(typeof(ResultsHandler))) - { - return new ResultsHandler(new ResultsHandlerAdapter(target).Handle); - } - else if (interfaceType.Equals(typeof(SyncResultsHandler))) - { - return new SyncResultsHandler(new SyncResultsHandlerAdapter(target).Handle); - } - else - { - throw new InvalidOperationException("Unhandled case: " + interfaceType); - } - } - } - #endregion - - #region LoggingProxy - public class LoggingProxy : InvocationHandler - { - private readonly SafeType _op; - private readonly object _target; - - public LoggingProxy(SafeType api, object target) - { - _op = api; - _target = target; - } - /// - /// Log all operations. - /// - public Object Invoke(Object proxy, MethodInfo method, Object[] args) - { - //do not proxy equals, hashCode, toString - if (method.DeclaringType.Equals(typeof(object))) - { - return method.Invoke(this, args); - } - StringBuilder bld = new StringBuilder(); - bld.Append("Enter: "); - AddMethodName(bld, method); - bld.Append('('); - for (int i = 0; args != null && i < args.Length; i++) - { - if (i != 0) - { - bld.Append(", "); - } - bld.Append('{').Append(i).Append('}'); - } - bld.Append(')'); - // write out trace header - Trace.TraceInformation(bld.ToString(), args); - // invoke the method - try - { - object ret = method.Invoke(_target, args); - // clear out buffer. - bld.Length = 0; - bld.Append("Return: "); - AddMethodName(bld, method); - bld.Append("({0})"); - Trace.TraceInformation(bld.ToString(), ret); - return ret; - } - catch (TargetInvocationException e) - { - Exception root = e.InnerException; - ExceptionUtil.PreserveStackTrace(root); - throw root; - } - } - - private void AddMethodName(StringBuilder bld, MethodInfo method) - { - bld.Append(_op.RawType.Name); - bld.Append('.'); - bld.Append(method.Name); - } - } - #endregion -} \ No newline at end of file diff --git a/FrameworkInternal/ApiLocal.cs b/FrameworkInternal/ApiLocal.cs deleted file mode 100644 index 0acc3c5..0000000 --- a/FrameworkInternal/ApiLocal.cs +++ /dev/null @@ -1,1194 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Diagnostics; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Common.Pooling; -using Org.IdentityConnectors.Common.Proxy; -using Org.IdentityConnectors.Framework.Api; -using Org.IdentityConnectors.Framework.Api.Operations; -using Org.IdentityConnectors.Framework.Common; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Common.Exceptions; -using Org.IdentityConnectors.Framework.Common.Serializer; -using Org.IdentityConnectors.Framework.Impl.Api.Remote; -using Org.IdentityConnectors.Framework.Impl.Api.Local.Operations; -using Org.IdentityConnectors.Framework.Spi; -using Org.IdentityConnectors.Framework.Spi.Operations; -using System.Collections.Generic; -using System.Globalization; -using System.Reflection; -using System.Resources; -using System.Threading; -using System.IO; -using System.Linq; -namespace Org.IdentityConnectors.Framework.Impl.Api.Local -{ - #region ConnectorPoolManager - public class ConnectorPoolManager - { - private class ConnectorPoolKey - { - private readonly ConnectorKey _connectorKey; - private readonly ConfigurationPropertiesImpl _configProperties; - private readonly ObjectPoolConfiguration _poolingConfig; - public ConnectorPoolKey(ConnectorKey connectorKey, - ConfigurationPropertiesImpl configProperties, - ObjectPoolConfiguration poolingConfig) - { - _connectorKey = connectorKey; - _configProperties = configProperties; - _poolingConfig = poolingConfig; - } - public override int GetHashCode() - { - return _connectorKey.GetHashCode(); - } - public override bool Equals(Object o) - { - if (o is ConnectorPoolKey) - { - ConnectorPoolKey other = (ConnectorPoolKey)o; - if (!_connectorKey.Equals(other._connectorKey)) - { - return false; - } - if (!_configProperties.Equals(other._configProperties)) - { - return false; - } - if (!_poolingConfig.Equals(other._poolingConfig)) - { - return false; - } - return true; - } - return false; - } - } - - private class ConnectorPoolHandler : ObjectPoolHandler - { - private readonly APIConfigurationImpl _apiConfiguration; - private readonly LocalConnectorInfoImpl _localInfo; - public ConnectorPoolHandler(APIConfigurationImpl apiConfiguration, - LocalConnectorInfoImpl localInfo) - { - _apiConfiguration = apiConfiguration; - _localInfo = localInfo; - } - public PoolableConnector NewObject() - { - Configuration config = - CSharpClassProperties.CreateBean((ConfigurationPropertiesImpl)_apiConfiguration.ConfigurationProperties, - _localInfo.ConnectorConfigurationClass); - PoolableConnector connector = - (PoolableConnector)_localInfo.ConnectorClass.CreateInstance(); - connector.Init(config); - return connector; - } - public void TestObject(PoolableConnector obj) - { - obj.CheckAlive(); - } - public void DisposeObject(PoolableConnector obj) - { - obj.Dispose(); - } - } - - /// - /// Cache of the various _pools.. - /// - private static readonly IDictionary> - _pools = new Dictionary>(); - - - /// - /// Get a object pool for this connector if it supports connector pooling. - /// - public static ObjectPool GetPool(APIConfigurationImpl impl, - LocalConnectorInfoImpl localInfo) - { - ObjectPool pool = null; - // determine if this connector wants generic connector pooling.. - if (impl.IsConnectorPoolingSupported) - { - ConnectorPoolKey key = - new ConnectorPoolKey( - impl.ConnectorInfo.ConnectorKey, - (ConfigurationPropertiesImpl)impl.ConfigurationProperties, - impl.ConnectorPoolConfiguration); - - lock (_pools) - { - // get the pool associated.. - pool = CollectionUtil.GetValue(_pools, key, null); - // create a new pool if it doesn't exist.. - if (pool == null) - { - Trace.TraceInformation("Creating new pool: " + - impl.ConnectorInfo.ConnectorKey); - // this instance is strictly used for the pool.. - pool = new ObjectPool( - new ConnectorPoolHandler(impl, localInfo), - impl.ConnectorPoolConfiguration); - // add back to the map of _pools.. - _pools[key] = pool; - } - } - } - return pool; - } - - public static void Dispose() - { - lock (_pools) - { - // close each pool.. - foreach (ObjectPool pool in _pools.Values) - { - try - { - pool.Shutdown(); - } - catch (Exception e) - { - TraceUtil.TraceException("Failed to close pool", e); - } - } - // clear the map of all _pools.. - _pools.Clear(); - } - } - } - #endregion - - #region CSharpClassProperties - internal static class CSharpClassProperties - { - public static ConfigurationPropertiesImpl - CreateConfigurationProperties(Configuration defaultObject) - { - SafeType config = SafeType.Get(defaultObject); - ConfigurationPropertiesImpl properties = - new ConfigurationPropertiesImpl(); - IList temp = - new List(); - IDictionary descs = GetFilteredProperties(config); - - foreach (PropertyInfo desc in descs.Values) - { - - String name = desc.Name; - - // get the configuration options.. - ConfigurationPropertyAttribute options = - GetPropertyOptions(desc); - // use the options to set internal properties.. - int order = 0; - String helpKey = name + ".help"; - String displKey = name + ".display"; - bool confidential = false; - bool required = false; - if (options != null) - { - // determine the display and help keys.. - if (!StringUtil.IsBlank(options.HelpMessageKey)) - { - helpKey = options.HelpMessageKey; - } - if (!StringUtil.IsBlank(options.DisplayMessageKey)) - { - displKey = options.DisplayMessageKey; - } - // determine the order.. - order = options.Order; - required = options.Required; - confidential = options.Confidential; - } - Type type = desc.PropertyType; - if (!FrameworkUtil.IsSupportedConfigurationType(type)) - { - const String MSG = "Property type ''{0}'' is not supported."; - throw new ArgumentException(String.Format(MSG, type)); - } - - Object value = desc.GetValue(defaultObject, null); - - ConfigurationPropertyImpl prop = new ConfigurationPropertyImpl(); - prop.IsConfidential = confidential; - prop.IsRequired = required; - prop.DisplayMessageKey = displKey; - prop.HelpMessageKey = helpKey; - prop.Name = name; - prop.Order = order; - prop.Value = value; - prop.ValueType = type; - prop.Operations = options == null ? null : TranslateOperations(options.Operations); - - temp.Add(prop); - - } - properties.Properties = (temp); - return properties; - } - - private static ICollection> TranslateOperations(SafeType[] ops) - { - ICollection> set = - new HashSet>(); - foreach (SafeType spi in ops) - { - CollectionUtil.AddAll(set, FrameworkUtil.Spi2Apis(spi)); - } - return set; - } - - public static Configuration - CreateBean(ConfigurationPropertiesImpl properties, - SafeType configType) - { - Configuration rv = configType.CreateInstance(); - rv.ConnectorMessages = properties.Parent.ConnectorInfo.Messages; - MergeIntoBean(properties, rv); - return rv; - } - - public static void - MergeIntoBean(ConfigurationPropertiesImpl properties, - Configuration config) - { - SafeType configType = - SafeType.Get(config); - IDictionary descriptors = - GetFilteredProperties(configType); - foreach (ConfigurationPropertyImpl property in properties.Properties) - { - String name = property.Name; - PropertyInfo desc = - CollectionUtil.GetValue(descriptors, name, null); - if (desc == null) - { - String FMT = - "Class ''{0}'' does not have a property ''{1}''."; - String MSG = String.Format(FMT, - configType.RawType.Name, - name); - throw new ArgumentException(MSG); - } - object val = property.Value; - //some value types such as arrays - //are mutable. make sure the config object - //has its own copy - val = SerializerUtil.CloneObject(val); - desc.SetValue(config, val, null); - } - } - - private static IDictionary - GetFilteredProperties(SafeType config) - { - IDictionary rv = - new Dictionary(); - PropertyInfo[] descriptors = config.RawType.GetProperties(); - foreach (PropertyInfo descriptor in descriptors) - { - String propName = descriptor.Name; - if (!descriptor.CanWrite) - { - //if there's no setter, ignore it - continue; - } - if ("ConnectorMessages".Equals(propName)) - { - continue; - } - if (!descriptor.CanRead) - { - const String FMT = - "Found setter ''{0}'' but not the corresponding getter."; - String MSG = String.Format(FMT, propName); - throw new ArgumentException(MSG); - } - rv[propName] = descriptor; - } - return rv; - } - - /// - /// Get the option from the property. - /// - private static ConfigurationPropertyAttribute GetPropertyOptions( - PropertyInfo propertyInfo) - { - Object[] objs = - propertyInfo.GetCustomAttributes( - typeof(ConfigurationPropertyAttribute), true); - if (objs.Length == 0) - { - return null; - } - else - { - return (ConfigurationPropertyAttribute)objs[0]; - } - } - - } - #endregion - - #region LocalConnectorInfoManagerImpl - internal class LocalConnectorInfoManagerImpl : ConnectorInfoManager - { - private IList _connectorInfo; - - public LocalConnectorInfoManagerImpl() - { - _connectorInfo = new List(); - Assembly assembly = Assembly.GetExecutingAssembly(); - FileInfo thisAssemblyFile = - new FileInfo(assembly.Location); - DirectoryInfo directory = - thisAssemblyFile.Directory; - FileInfo[] files = - directory.GetFiles("*.Connector.dll"); - foreach (FileInfo file in files) - { - Assembly lib = - Assembly.LoadFrom(file.ToString()); - CollectionUtil.AddAll(_connectorInfo, - ProcessAssembly(lib)); - } - // also handle connector DLL file names with a version - FileInfo[] versionedFiles = directory.GetFiles("*.Connector-*.dll"); - foreach (FileInfo versionedFile in versionedFiles) - { - Assembly lib = - Assembly.LoadFrom(versionedFile.ToString()); - CollectionUtil.AddAll(_connectorInfo, - ProcessAssembly(lib)); - } - } - - private IList ProcessAssembly(Assembly assembly) - { - IList rv = new List(); - - Type[] types = null; - try - { - types = assembly.GetTypes(); - } - catch (Exception e) - { - TraceUtil.TraceException("Unable to load assembly: " + assembly.FullName + ". Assembly will be ignored.", e); - } - - foreach (Type type in types) - { - Object[] attributes = type.GetCustomAttributes( - typeof(ConnectorClassAttribute), - false); - if (attributes.Length > 0) - { - ConnectorClassAttribute attribute = - (ConnectorClassAttribute)attributes[0]; - LocalConnectorInfoImpl info = - CreateConnectorInfo(assembly, type, attribute); - rv.Add(info); - } - } - return rv; - } - - private LocalConnectorInfoImpl CreateConnectorInfo(Assembly assembly, - Type rawConnectorClass, - ConnectorClassAttribute attribute) - { - String fileName = assembly.Location; - if (!typeof(Connector).IsAssignableFrom(rawConnectorClass)) - { - String MSG = ("File " + fileName + - " declares a connector " + rawConnectorClass + - " that does not implement Connector."); - throw new ConfigurationException(MSG); - } - SafeType connectorClass = - SafeType.ForRawType(rawConnectorClass); - SafeType connectorConfigurationClass = attribute.ConnectorConfigurationType; - if (connectorConfigurationClass == null) - { - String MSG = ("File " + fileName + - " contains a ConnectorInfo attribute " + - "with no connector configuration class."); - throw new ConfigurationException(MSG); - } - String connectorDisplayNameKey = - attribute.ConnectorDisplayNameKey; - if (connectorDisplayNameKey == null) - { - String MSG = ("File " + fileName + - " contains a ConnectorInfo attribute " + - "with no connector display name."); - throw new ConfigurationException(MSG); - } - ConnectorKey key = - new ConnectorKey(assembly.GetName().Name, - assembly.GetName().Version.ToString(), - connectorClass.RawType.Namespace + "." + connectorClass.RawType.Name); - LocalConnectorInfoImpl rv = new LocalConnectorInfoImpl(); - rv.ConnectorClass = connectorClass; - rv.ConnectorConfigurationClass = connectorConfigurationClass; - rv.ConnectorDisplayNameKey = connectorDisplayNameKey; - rv.ConnectorKey = key; - rv.DefaultAPIConfiguration = CreateDefaultAPIConfiguration(rv); - rv.Messages = LoadMessages(assembly, rv, attribute.MessageCatalogPaths); - return rv; - } - - private APIConfigurationImpl - CreateDefaultAPIConfiguration(LocalConnectorInfoImpl localInfo) - { - SafeType connectorClass = - localInfo.ConnectorClass; - APIConfigurationImpl rv = new APIConfigurationImpl(); - Configuration config = - localInfo.ConnectorConfigurationClass.CreateInstance(); - bool pooling = IsPoolingSupported(connectorClass); - rv.IsConnectorPoolingSupported = pooling; - rv.ConfigurationProperties = (CSharpClassProperties.CreateConfigurationProperties(config)); - rv.ConnectorInfo = (localInfo); - rv.SupportedOperations = (FrameworkUtil.GetDefaultSupportedOperations(connectorClass)); - return rv; - } - - private static bool IsPoolingSupported(SafeType clazz) - { - return ReflectionUtil.IsParentTypeOf(typeof(PoolableConnector), clazz.RawType); - } - - /// - /// Given an assembly, returns the list of cultures that - /// it is localized for - /// - /// - /// - private CultureInfo[] GetLocalizedCultures(Assembly assembly) - { - FileInfo assemblyFile = - new FileInfo(assembly.Location); - DirectoryInfo directory = - assemblyFile.Directory; - IList temp = new List(); - DirectoryInfo[] subdirs = directory.GetDirectories(); - foreach (DirectoryInfo subdir in subdirs) - { - String name = subdir.Name; - CultureInfo cultureInfo; - //get the culture if the directory is the name of the - //culture - try - { - cultureInfo = new CultureInfo(name); - } - catch (ArgumentException) - { - //invalid culture - continue; - } - //see if there's a satellite assembly for this - try - { - assembly.GetSatelliteAssembly(cultureInfo); - } - catch (Exception) - { - //invalid assembly - continue; - } - temp.Add(cultureInfo); - } - temp.Add(CultureInfo.InvariantCulture); - return temp.ToArray(); - } - - private ConnectorMessagesImpl LoadMessages(Assembly assembly, - LocalConnectorInfoImpl info, - String[] nameBases) - { - if (nameBases == null || nameBases.Length == 0) - { - String pkage = - info.ConnectorClass.RawType.Namespace; - nameBases = new String[] { pkage + ".Messages" }; - } - ConnectorMessagesImpl rv = new ConnectorMessagesImpl(); - CultureInfo[] cultures = GetLocalizedCultures(assembly); - for (int i = nameBases.Length - 1; i >= 0; i--) - { - String nameBase = nameBases[i]; - ResourceManager manager = new ResourceManager(nameBase, assembly); - foreach (CultureInfo culture in cultures) - { - ResourceSet resourceSet = manager.GetResourceSet(culture, true, false); - if (resourceSet != null) - { - IDictionary temp = - CollectionUtil.GetValue(rv.Catalogs, culture, null); - if (temp == null) - { - temp = new Dictionary(); - rv.Catalogs[culture] = temp; - } - foreach (System.Collections.DictionaryEntry entry in resourceSet) - { - String key = "" + entry.Key; - String val = "" + entry.Value; - temp[key] = val; - } - } - } - } - - return rv; - } - - public ConnectorInfo FindConnectorInfo(ConnectorKey key) - { - foreach (ConnectorInfo info in _connectorInfo) - { - if (info.ConnectorKey.Equals(key)) - { - return info; - } - } - return null; - } - public IList ConnectorInfos - { - get - { - return CollectionUtil.AsReadOnlyList(_connectorInfo); - } - } - } - #endregion - - #region LocalConnectorInfoImpl - /// - /// Internal class, public only for unit tests - /// - public class LocalConnectorInfoImpl : AbstractConnectorInfo - { - public RemoteConnectorInfoImpl ToRemote() - { - RemoteConnectorInfoImpl rv = new RemoteConnectorInfoImpl(); - rv.ConnectorDisplayNameKey = ConnectorDisplayNameKey; - rv.ConnectorKey = ConnectorKey; - rv.DefaultAPIConfiguration = DefaultAPIConfiguration; - rv.Messages = Messages; - return rv; - } - public SafeType ConnectorClass { get; set; } - public SafeType ConnectorConfigurationClass { get; set; } - } - #endregion - - #region LocalConnectorFacadeImpl - internal class LocalConnectorFacadeImpl : AbstractConnectorFacade - { - // ======================================================================= - // Constants - // ======================================================================= - /// - /// Map the API interfaces to their implementation counterparts. - /// - private static readonly IDictionary, ConstructorInfo> API_TO_IMPL = - new Dictionary, ConstructorInfo>(); - - private static void AddImplementation(SafeType inter, - SafeType impl) - { - ConstructorInfo info = - impl.RawType.GetConstructor(new Type[]{typeof(ConnectorOperationalContext), - typeof(Connector)}); - if (info == null) - { - throw new ArgumentException(impl + " does not define the proper constructor"); - } - API_TO_IMPL[inter] = info; - } - - static LocalConnectorFacadeImpl() - { - AddImplementation(SafeType.Get(), - SafeType.Get()); - AddImplementation(SafeType.Get(), - SafeType.Get()); - AddImplementation(SafeType.Get(), - SafeType.Get()); - AddImplementation(SafeType.Get(), - SafeType.Get()); - AddImplementation(SafeType.Get(), - SafeType.Get()); - AddImplementation(SafeType.Get(), - SafeType.Get()); - AddImplementation(SafeType.Get(), - SafeType.Get()); - AddImplementation(SafeType.Get(), - SafeType.Get()); - AddImplementation(SafeType.Get(), - SafeType.Get()); - AddImplementation(SafeType.Get(), - SafeType.Get()); - AddImplementation(SafeType.Get(), - SafeType.Get()); - } - - // ======================================================================= - // Fields - // ======================================================================= - /// - /// Pool used to acquire connection from to use during operations. - /// - - /// - /// The connector info - /// - private readonly LocalConnectorInfoImpl connectorInfo; - - /// - /// Builds up the maps of supported operations and calls. - /// - public LocalConnectorFacadeImpl(LocalConnectorInfoImpl connectorInfo, - APIConfigurationImpl apiConfiguration) - : base(apiConfiguration) - { - this.connectorInfo = connectorInfo; - } - - // ======================================================================= - // ConnectorFacade Interface - // ======================================================================= - - protected override APIOperation GetOperationImplementation(SafeType api) - { - APIOperation proxy; - //first create the inner proxy - this is the proxy that obtaining - //a connection from the pool, etc - //NOTE: we want to skip this part of the proxy for - //validate op, but we will want the timeout proxy - if (api.RawType.Equals(typeof(ValidateApiOp))) - { - OperationalContext context = - new OperationalContext(connectorInfo, GetAPIConfiguration()); - proxy = new ValidateImpl(context); - } - else if (api.RawType.Equals(typeof(GetApiOp))) - { - ConstructorInfo constructor = - API_TO_IMPL[SafeType.Get()]; - ConnectorOperationalContext context = - new ConnectorOperationalContext(connectorInfo, - GetAPIConfiguration(), - GetPool()); - - ConnectorAPIOperationRunnerProxy handler = - new ConnectorAPIOperationRunnerProxy(context, constructor); - proxy = - new GetImpl((SearchApiOp)NewAPIOperationProxy(SafeType.Get(), handler)); - } - else - { - ConstructorInfo constructor = - API_TO_IMPL[api]; - ConnectorOperationalContext context = - new ConnectorOperationalContext(connectorInfo, - GetAPIConfiguration(), - GetPool()); - - ConnectorAPIOperationRunnerProxy handler = - new ConnectorAPIOperationRunnerProxy(context, constructor); - proxy = - NewAPIOperationProxy(api, handler); - } - - //TODO: timeout - - // add logging proxy.. - proxy = CreateLoggingProxy(api, proxy); - return proxy; - } - private ObjectPool GetPool() - { - return ConnectorPoolManager.GetPool(GetAPIConfiguration(), connectorInfo); - } - } - #endregion - - #region ObjectPool - public class ObjectPool where T : class - { - /// - /// Statistics bean - /// - public sealed class Statistics - { - private readonly int _numIdle; - private readonly int _numActive; - - internal Statistics(int numIdle, int numActive) - { - _numIdle = numIdle; - _numActive = numActive; - } - - /// - /// Returns the number of idle objects - /// - public int NumIdle - { - get - { - return _numIdle; - } - } - - /// - /// Returns the number of active objects - /// - public int NumActive - { - get - { - return _numActive; - } - } - } - - /// - /// An object plus additional book-keeping - /// information about the object - /// - private class PooledObject where T2 : class - { - /// - /// The underlying object - /// - private readonly T2 _object; - - /// - /// True if this is currently active, false if - /// it is idle - /// - private bool _isActive; - - /// - /// Last state change (change from active to - /// idle or vice-versa) - /// - private long _lastStateChangeTimestamp; - - /// - /// Is this a freshly created object (never been pooled)? - /// - private bool _isNew; - - public PooledObject(T2 obj) - { - _object = obj; - _isNew = true; - Touch(); - } - - public T2 Object - { - get - { - return _object; - } - } - - public bool IsActive - { - get - { - return _isActive; - } - set - { - if (_isActive != value) - { - Touch(); - _isActive = value; - } - } - } - - public bool IsNew - { - get - { - return _isNew; - } - set - { - _isNew = value; - } - } - - - private void Touch() - { - _lastStateChangeTimestamp = DateTimeUtil.GetCurrentUtcTimeMillis(); - } - - public long LastStateChangeTimestamp - { - get - { - return _lastStateChangeTimestamp; - } - } - } - - /// - /// The lock object we use for everything - /// - private readonly Object LOCK = new Object(); - - /// - /// Map from the object to the - /// PooledObject (use IdentityHashMap so it's - /// always object equality) - /// - private readonly IDictionary> - _activeObjects = CollectionUtil.NewIdentityDictionary>(); - - /// - /// Queue of idle objects. - /// - /// - /// The one that has - /// been idle for the longest comes first in the queue - /// - private readonly LinkedList> - _idleObjects = new LinkedList>(); - - /// - /// ObjectPoolHandler we use for managing object lifecycle - /// - private readonly ObjectPoolHandler _handler; - - /// - /// Configuration for this pool. - /// - private readonly ObjectPoolConfiguration _config; - - /// - /// Is the pool shutdown - /// - private bool _isShutdown; - - /// - /// Create a new ObjectPool - /// - /// Handler for objects - /// Configuration for the pool - public ObjectPool(ObjectPoolHandler handler, - ObjectPoolConfiguration config) - { - - Assertions.NullCheck(handler, "handler"); - Assertions.NullCheck(config, "config"); - - _handler = handler; - //clone it - _config = - (ObjectPoolConfiguration)SerializerUtil.CloneObject(config); - //validate it - _config.Validate(); - - } - - /// - /// Return an object to the pool - /// - /// - public void ReturnObject(T obj) - { - Assertions.NullCheck(obj, "object"); - lock (LOCK) - { - //remove it from the active list - PooledObject pooled = - CollectionUtil.GetValue(_activeObjects, obj, null); - - //they are attempting to return something - //we haven't allocated (or that they've - //already returned) - if (pooled == null) - { - throw new InvalidOperationException("Attempt to return an object not in the pool: " + obj); - } - _activeObjects.Remove(obj); - - //set it to idle and add to idle list - //(this might get evicted right away - //by evictIdleObjects if we're over the - //limit or if we're shutdown) - pooled.IsActive = (false); - pooled.IsNew = (false); - _idleObjects.AddLast(pooled); - - //finally evict idle objects - EvictIdleObjects(); - - //wake anyone up who was waiting on a object - Monitor.PulseAll(LOCK); - } - } - - /// - /// Borrow an object from the pool. - /// - /// An object - public T BorrowObject() - { - while (true) - { - PooledObject rv = BorrowObjectNoTest(); - try - { - //make sure we are testing it outside - //of synchronization. otherwise this - //can create an IO bottleneck - _handler.TestObject(rv.Object); - return rv.Object; - } - catch (Exception e) - { - //it's bad - remove from active objects - lock (LOCK) - { - _activeObjects.Remove(rv.Object); - } - DisposeNoException(rv.Object); - //if it's a new object, break out of the loop - //immediately - if (rv.IsNew) - { - throw e; - } - } - } - } - - /// - /// Borrow an object from the pool, but don't test - /// it (it gets tested by the caller *outside* of - /// synchronization) - /// - /// the object - private PooledObject BorrowObjectNoTest() - { - //time when the call began - long startTime = DateTimeUtil.GetCurrentUtcTimeMillis(); - - lock (LOCK) - { - EvictIdleObjects(); - while (true) - { - if (_isShutdown) - { - throw new InvalidOperationException("Object pool already shutdown"); - } - - PooledObject pooledConn = null; - - //first try to recycle an idle object - if (_idleObjects.Count > 0) - { - pooledConn = _idleObjects.First(); - _idleObjects.RemoveFirst(); - } - //otherwise, allocate a new object if - //below the limit - else if (_activeObjects.Count < _config.MaxObjects) - { - pooledConn = - new PooledObject(_handler.NewObject()); - } - - //if there's an object available, return it - //and break out of the loop - if (pooledConn != null) - { - pooledConn.IsActive = (true); - _activeObjects[pooledConn.Object] = - pooledConn; - return pooledConn; - } - - //see if we haven't timed-out yet - long elapsed = - DateTimeUtil.GetCurrentUtcTimeMillis() - startTime; - long remaining = _config.MaxWait - elapsed; - - //wait if we haven't timed out - if (remaining > 0) - { - Monitor.Wait(LOCK, (int)remaining); - } - else - { - //otherwise throw - throw new ConnectorException("Max objects exceeded"); - } - } - } - } - - /// - /// Closes any idle objects in the pool. - /// - /// - /// Existing active objects will remain alive and - /// be allowed to shutdown gracefully, but no more - /// objects will be allocated. - /// - public void Shutdown() - { - lock (LOCK) - { - _isShutdown = true; - //just evict idle objects - //if there are any active objects still - //going, leave them alone so they can return - //gracefully - EvictIdleObjects(); - //wake anyone up who was waiting on an object - Monitor.PulseAll(LOCK); - } - } - - /// - /// Gets a snapshot of the pool's stats at a point in time. - /// - /// The statistics - public Statistics GetStatistics() - { - lock (LOCK) - { - return new Statistics(_idleObjects.Count, - _activeObjects.Count); - } - } - - /// - /// Evicts idle objects as needed (evicts - /// all idle objects if we're shutdown) - /// - private void EvictIdleObjects() - { - while (TooManyIdleObjects()) - { - PooledObject conn = _idleObjects.First(); - _idleObjects.RemoveFirst(); - DisposeNoException(conn.Object); - } - } - - /// - /// Returns true if any of the following are true: - /// - /// - /// We're shutdown and there are idle objects - /// - /// - /// - /// Max idle objects exceeded - /// - /// - /// - /// Min idle objects exceeded and there are old objects - /// - /// - /// - /// - private bool TooManyIdleObjects() - { - - if (_isShutdown && _idleObjects.Count > 0) - { - return true; - } - - if (_config.MaxIdle < _idleObjects.Count) - { - return true; - } - if (_config.MinIdle >= _idleObjects.Count) - { - return false; - } - - PooledObject oldest = - _idleObjects.First(); - - long age = - (DateTimeUtil.GetCurrentUtcTimeMillis() - oldest.LastStateChangeTimestamp); - - - return age > _config.MinEvictableIdleTimeMillis; - } - - /// - /// Dispose of an object, but don't throw any exceptions - /// - /// - private void DisposeNoException(T obj) - { - try - { - _handler.DisposeObject(obj); - } - catch (Exception e) - { - TraceUtil.TraceException("disposeObject() is not supposed to throw", e); - } - } - } - #endregion - - #region ObjectPoolHandler - public interface ObjectPoolHandler where T : class - { - T NewObject(); - void TestObject(T obj); - void DisposeObject(T obj); - } - #endregion -} \ No newline at end of file diff --git a/FrameworkInternal/ApiLocalOperations.cs b/FrameworkInternal/ApiLocalOperations.cs deleted file mode 100644 index f5c1474..0000000 --- a/FrameworkInternal/ApiLocalOperations.cs +++ /dev/null @@ -1,1613 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Common.Pooling; -using Org.IdentityConnectors.Common.Proxy; -using Org.IdentityConnectors.Common.Script; -using Org.IdentityConnectors.Common.Security; -using Org.IdentityConnectors.Framework.Api.Operations; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Common.Objects.Filters; -using Org.IdentityConnectors.Framework.Common.Exceptions; -using Org.IdentityConnectors.Framework.Common.Serializer; -using Org.IdentityConnectors.Framework.Spi; -using Org.IdentityConnectors.Framework.Spi.Operations; -using System.Reflection; -using System.Collections.Generic; -using System.Linq; - -namespace Org.IdentityConnectors.Framework.Impl.Api.Local.Operations -{ - #region APIOperationRunner - /// - /// NOTE: internal class, public only for unit tests - /// Base class for API operation runners. - /// - public abstract class APIOperationRunner - { - /// - /// Context that has all the information required to execute an operation. - /// - private readonly OperationalContext _context; - - /// - /// Creates the API operation so it can called multiple times. - /// - public APIOperationRunner(OperationalContext context) - { - _context = context; - //TODO: verify this - // get the APIOperation that this class implements.. - //List> apiOps = getInterfaces(this - //.getClass(), APIOperation.class); - // there should be only one.. - //if (apiOps.size() > 1) { - // final String MSG = "Must only implement one operation."; - // throw new IllegalStateException(MSG); - //} - } - - /// - /// Get the current operational context. - /// - public OperationalContext GetOperationalContext() - { - return _context; - } - - } - #endregion - - #region ConnectorAPIOperationRunner - /// - /// NOTE: internal class, public only for unit tests - /// Subclass of APIOperationRunner for operations that require a connector. - /// - public abstract class ConnectorAPIOperationRunner : APIOperationRunner - { - /// - /// The connector instance - /// - private readonly Connector _connector; - - /// - /// Creates the API operation so it can called multiple times. - /// - public ConnectorAPIOperationRunner(ConnectorOperationalContext context, - Connector connector) - : base(context) - { - _connector = connector; - } - - public Connector GetConnector() - { - return _connector; - } - - public ObjectNormalizerFacade GetNormalizer(ObjectClass oclass) - { - AttributeNormalizer norm = null; - Connector connector = GetConnector(); - if (connector is AttributeNormalizer) - { - norm = (AttributeNormalizer)connector; - } - return new ObjectNormalizerFacade(oclass, norm); - } - } - #endregion - - #region ConnectorAPIOperationRunnerProxy - /// - /// Proxy for APIOperationRunner that takes care of setting up underlying - /// connector and creating the implementation of APIOperationRunner. - /// - /// - /// The implementation of APIOperationRunner gets created whenever the - /// actual method is invoked. - /// - internal class ConnectorAPIOperationRunnerProxy : InvocationHandler - { - /// - /// The operational context - /// - private readonly ConnectorOperationalContext _context; - - /// - /// The implementation constructor. - /// - /// - /// The instance is lazily created upon - /// invocation - /// - private readonly ConstructorInfo _runnerImplConstructor; - - /// - /// Create an APIOperationRunnerProxy - /// - /// The operational context - /// The implementation constructor. Implementation - /// must define a two-argument constructor(OperationalContext,Connector) - public ConnectorAPIOperationRunnerProxy(ConnectorOperationalContext context, - ConstructorInfo runnerImplConstructor) - { - _context = context; - _runnerImplConstructor = runnerImplConstructor; - } - - public Object Invoke(Object proxy, MethodInfo method, object[] args) - { - //do not proxy equals, hashCode, toString - if (method.DeclaringType.Equals(typeof(object))) - { - return method.Invoke(this, args); - } - object ret = null; - Connector connector = null; - ObjectPool pool = _context.GetPool(); - // get the connector class.. - SafeType connectorClazz = _context.GetConnectorClass(); - try - { - // pooling is implemented get one.. - if (pool != null) - { - connector = pool.BorrowObject(); - } - else - { - // get a new instance of the connector.. - connector = connectorClazz.CreateInstance(); - // initialize the connector.. - connector.Init(_context.GetConfiguration()); - } - APIOperationRunner runner = - (APIOperationRunner)_runnerImplConstructor.Invoke(new object[]{ - _context, - connector}); - ret = method.Invoke(runner, args); - // call out to the operation.. - } - catch (TargetInvocationException e) - { - Exception root = e.InnerException; - ExceptionUtil.PreserveStackTrace(root); - throw root; - } - finally - { - // make sure dispose of the connector properly - if (connector != null) - { - // determine if there was a pool.. - if (pool != null) - { - try - { - //try to return it to the pool even though an - //exception may have happened that leaves it in - //a bad state. The contract of checkAlive - //is that it will tell you if the connector is - //still valid and so we leave it up to the pool - //and connector to work it out. - pool.ReturnObject((PoolableConnector)connector); - } - catch (Exception e) - { - //don't let pool exceptions propogate or mask - //other exceptions. do log it though. - TraceUtil.TraceException(null, e); - } - } - //not pooled - just dispose - else - { - //dispose it not supposed to throw, but just in case, - //catch the exception and log it so we know about it - //but don't let the exception prevent additional - //cleanup that needs to happen - try - { - connector.Dispose(); - } - catch (Exception e) - { - //log this though - TraceUtil.TraceException(null, e); - } - } - } - } - return ret; - } - } - #endregion - - #region ConnectorOperationalContext - /// - /// NOTE: internal class, public only for unit tests - /// Simple structure to pass more variables through the constructor of - /// . - /// - public class ConnectorOperationalContext : OperationalContext - { - private readonly ObjectPool _pool; - - public ConnectorOperationalContext(LocalConnectorInfoImpl connectorInfo, - APIConfigurationImpl apiConfiguration, - ObjectPool pool) - : base(connectorInfo, apiConfiguration) - { - _pool = pool; - } - - public ObjectPool GetPool() - { - return _pool; - } - - - public SafeType GetConnectorClass() - { - return GetConnectorInfo().ConnectorClass; - } - - } - #endregion - - #region AuthenticationImpl - internal class AuthenticationImpl : ConnectorAPIOperationRunner, - AuthenticationApiOp - { - /// - /// Pass the configuration etc to the abstract class. - /// - public AuthenticationImpl(ConnectorOperationalContext context, - Connector connector) - : base(context, connector) - { - } - - /// - /// Authenticate using the basic credentials. - /// - /// - public Uid Authenticate(ObjectClass objectClass, String username, GuardedString password, OperationOptions options) - { - Assertions.NullCheck(objectClass, "objectClass"); - Assertions.NullCheck(username, "username"); - Assertions.NullCheck(password, "password"); - //convert null into empty - if (options == null) - { - options = new OperationOptionsBuilder().Build(); - } - return ((AuthenticateOp)GetConnector()).Authenticate(objectClass, username, password, options); - } - } - #endregion - - #region ResolveUsernameImpl - internal class ResolveUsernameImpl : ConnectorAPIOperationRunner, - ResolveUsernameApiOp - { - /// - /// Pass the configuration etc to the abstract class. - /// - public ResolveUsernameImpl(ConnectorOperationalContext context, - Connector connector) - : base(context, connector) - { - } - - /// - /// Resolve the username to an Uid. - /// - public Uid ResolveUsername(ObjectClass objectClass, String username, OperationOptions options) - { - Assertions.NullCheck(objectClass, "objectClass"); - Assertions.NullCheck(username, "username"); - //convert null into empty - if (options == null) - { - options = new OperationOptionsBuilder().Build(); - } - return ((ResolveUsernameOp)GetConnector()).ResolveUsername(objectClass, username, options); - } - } - #endregion - - #region CreateImpl - internal class CreateImpl : ConnectorAPIOperationRunner, - CreateApiOp - { - /// - /// Initializes the operation works. - /// - public CreateImpl(ConnectorOperationalContext context, - Connector connector) - : base(context, connector) - { - } - - /// - /// Calls the create method on the Connector side. - /// - /// - public Uid Create(ObjectClass oclass, ICollection attributes, OperationOptions options) - { - Assertions.NullCheck(oclass, "oclass"); - Assertions.NullCheck(attributes, "attributes"); - //convert null into empty - if (options == null) - { - options = new OperationOptionsBuilder().Build(); - } - HashSet dups = new HashSet(); - foreach (ConnectorAttribute attr in attributes) - { - if (dups.Contains(attr.Name)) - { - throw new ArgumentException("Duplicate attribute name exists: " + attr.Name); - } - dups.Add(attr.Name); - } - if (oclass == null) - { - throw new ArgumentException("Required attribute ObjectClass not found!"); - } - Connector connector = GetConnector(); - ObjectNormalizerFacade normalizer = GetNormalizer(oclass); - ICollection normalizedAttributes = - normalizer.NormalizeAttributes(attributes); - // create the object.. - Uid ret = ((CreateOp)connector).Create(oclass, attributes, options); - return (Uid)normalizer.NormalizeAttribute(ret); - } - } - #endregion - - #region DeleteImpl - internal class DeleteImpl : ConnectorAPIOperationRunner, - DeleteApiOp - { - /// - /// Initializes the operation works. - /// - public DeleteImpl(ConnectorOperationalContext context, - Connector connector) - : base(context, connector) - { - } - /// - /// Calls the delete method on the Connector side. - /// - /// - public void Delete(ObjectClass objClass, Uid uid, OperationOptions options) - { - Assertions.NullCheck(objClass, "objClass"); - Assertions.NullCheck(uid, "uid"); - //convert null into empty - if (options == null) - { - options = new OperationOptionsBuilder().Build(); - } - Connector connector = GetConnector(); - ObjectNormalizerFacade normalizer = GetNormalizer(objClass); - // delete the object.. - ((DeleteOp)connector).Delete(objClass, - (Uid)normalizer.NormalizeAttribute(uid), - options); - } - } - #endregion - - #region AttributesToGetResultsHandler - public abstract class AttributesToGetResultsHandler - { - // ======================================================================= - // Fields - // ======================================================================= - private readonly string[] _attrsToGet; - - // ======================================================================= - // Constructors - // ======================================================================= - /// - /// Keep the attribute to get.. - /// - public AttributesToGetResultsHandler(string[] attrsToGet) - { - Assertions.NullCheck(attrsToGet, "attrsToGet"); - _attrsToGet = attrsToGet; - } - - /// - /// Simple method that clones the object and remove the attribute thats are - /// not in the set. - /// - /// case insensitive set of attribute names. - public ICollection ReduceToAttrsToGet( - ICollection attrs) - { - ICollection ret = new HashSet(); - IDictionary map = ConnectorAttributeUtil.ToMap(attrs); - foreach (string attrName in _attrsToGet) - { - ConnectorAttribute attr = CollectionUtil.GetValue(map, attrName, null); - // TODO: Should we throw if the attribute is not yet it was - // requested?? Or do we ignore because the API maybe asking - // for what the resource doesn't have?? - if (attr != null) - { - ret.Add(attr); - } - } - return ret; - } - public ConnectorObject ReduceToAttrsToGet(ConnectorObject obj) - { - // clone the object and reduce the attributes only the set of - // attributes. - ConnectorObjectBuilder bld = new ConnectorObjectBuilder(); - bld.SetUid(obj.Uid); - bld.SetName(obj.Name); - bld.ObjectClass = obj.ObjectClass; - ICollection objAttrs = obj.GetAttributes(); - ICollection attrs = ReduceToAttrsToGet(objAttrs); - bld.AddAttributes(attrs); - return bld.Build(); - } - } - #endregion - - #region SearchAttributesToGetResultsHandler - public sealed class SearchAttributesToGetResultsHandler : - AttributesToGetResultsHandler - { - // ======================================================================= - // Fields - // ======================================================================= - private readonly ResultsHandler _handler; - - // ======================================================================= - // Constructors - // ======================================================================= - public SearchAttributesToGetResultsHandler( - ResultsHandler handler, string[] attrsToGet) - : base(attrsToGet) - { - Assertions.NullCheck(handler, "handler"); - this._handler = handler; - } - - public bool Handle(ConnectorObject obj) - { - // clone the object and reduce the attributes only the set of - // attributes. - return _handler(ReduceToAttrsToGet(obj)); - } - } - #endregion - - #region SearchAttributesToGetResultsHandler - public sealed class SyncAttributesToGetResultsHandler : - AttributesToGetResultsHandler - { - // ======================================================================= - // Fields - // ======================================================================= - private readonly SyncResultsHandler _handler; - - // ======================================================================= - // Constructors - // ======================================================================= - public SyncAttributesToGetResultsHandler( - SyncResultsHandler handler, string[] attrsToGet) - : base(attrsToGet) - { - Assertions.NullCheck(handler, "handler"); - this._handler = handler; - } - - public bool Handle(SyncDelta delta) - { - SyncDeltaBuilder bld = new SyncDeltaBuilder(); - bld.Uid = delta.Uid; - bld.Token = delta.Token; - bld.DeltaType = delta.DeltaType; - if (delta.Object != null) - { - bld.Object = ReduceToAttrsToGet(delta.Object); - } - return _handler(bld.Build()); - } - } - #endregion - - #region DuplicateFilteringResultsHandler - public sealed class DuplicateFilteringResultsHandler - { - // ======================================================================= - // Fields - // ======================================================================= - private readonly ResultsHandler _handler; - private readonly HashSet _visitedUIDs = new HashSet(); - - private bool _stillHandling; - - // ======================================================================= - // Constructors - // ======================================================================= - /// - /// Filter chain for producers. - /// - /// Producer to filter. - public DuplicateFilteringResultsHandler(ResultsHandler handler) - { - // there must be a producer.. - if (handler == null) - { - throw new ArgumentException("Handler must not be null!"); - } - this._handler = handler; - } - - public bool Handle(ConnectorObject obj) - { - String uid = - obj.Uid.GetUidValue(); - if (!_visitedUIDs.Add(uid)) - { - //we've already seen this - don't pass it - //throw - return true; - } - _stillHandling = _handler(obj); - return _stillHandling; - } - - public bool IsStillHandling - { - get - { - return _stillHandling; - } - } - } - #endregion - - #region FilteredResultsHandler - public sealed class FilteredResultsHandler - { - // ======================================================================= - // Fields - // ======================================================================= - readonly ResultsHandler handler; - readonly Filter filter; - - // ======================================================================= - // Constructors - // ======================================================================= - /// - /// Filter chain for producers. - /// - /// Producer to filter. - /// Filter to use to accept objects. - public FilteredResultsHandler(ResultsHandler handler, Filter filter) - { - // there must be a producer.. - if (handler == null) - { - throw new ArgumentException("Producer must not be null!"); - } - this.handler = handler; - // use a default pass through filter.. - this.filter = filter == null ? new PassThruFilter() : filter; - } - - public bool Handle(ConnectorObject obj) - { - if (filter.Accept(obj)) - { - return handler(obj); - } - else - { - return true; - } - } - - /// - /// Use a pass thru filter to use if a null filter is provided. - /// - class PassThruFilter : Filter - { - public bool Accept(ConnectorObject obj) - { - return true; - } - } - } - #endregion - - #region GetImpl - /// - /// Uses to find the object that is referenced by the - /// provided. - /// - public class GetImpl : GetApiOp - { - readonly SearchApiOp op; - - private class ResultAdapter - { - private IList _list = new List(); - public bool Handle(ConnectorObject obj) - { - _list.Add(obj); - return false; - } - public ConnectorObject GetResult() - { - return _list.Count == 0 ? null : _list[0]; - } - } - - public GetImpl(SearchApiOp search) - { - this.op = search; - } - - public ConnectorObject GetObject(ObjectClass objClass, Uid uid, OperationOptions options) - { - Assertions.NullCheck(objClass, "objClass"); - Assertions.NullCheck(uid, "uid"); - //convert null into empty - if (options == null) - { - options = new OperationOptionsBuilder().Build(); - } - Filter filter = FilterBuilder.EqualTo(uid); - ResultAdapter adapter = new ResultAdapter(); - op.Search(objClass, filter, new ResultsHandler(adapter.Handle), options); - return adapter.GetResult(); - } - } - #endregion - - #region OperationalContext - /// - /// NOTE: internal class, public only for unit tests - /// OperationalContext - base class for operations that do not - /// require a connection. - /// - public class OperationalContext - { - /// - /// ConnectorInfo - /// - private readonly LocalConnectorInfoImpl connectorInfo; - - /// - /// Contains the . - /// - private readonly APIConfigurationImpl apiConfiguration; - - - public OperationalContext(LocalConnectorInfoImpl connectorInfo, - APIConfigurationImpl apiConfiguration) - { - this.connectorInfo = connectorInfo; - this.apiConfiguration = apiConfiguration; - } - - public Configuration GetConfiguration() - { - return CSharpClassProperties.CreateBean((ConfigurationPropertiesImpl)this.apiConfiguration.ConfigurationProperties, - connectorInfo.ConnectorConfigurationClass); - } - - protected LocalConnectorInfoImpl GetConnectorInfo() - { - return connectorInfo; - } - } - #endregion - - #region NormalizingResultsHandler - public class NormalizingResultsHandler - { - private readonly ResultsHandler _target; - private readonly ObjectNormalizerFacade _normalizer; - - public NormalizingResultsHandler(ResultsHandler target, - ObjectNormalizerFacade normalizer) - { - Assertions.NullCheck(target, "target"); - Assertions.NullCheck(normalizer, "normalizer"); - _target = target; - _normalizer = normalizer; - } - - - public bool Handle(ConnectorObject obj) - { - ConnectorObject normalized = _normalizer.NormalizeObject(obj); - return _target(normalized); - } - - } - #endregion - - #region NormalizingSyncResultsHandler - public class NormalizingSyncResultsHandler - { - private readonly SyncResultsHandler _target; - private readonly ObjectNormalizerFacade _normalizer; - - public NormalizingSyncResultsHandler(SyncResultsHandler target, - ObjectNormalizerFacade normalizer) - { - Assertions.NullCheck(target, "target"); - Assertions.NullCheck(normalizer, "normalizer"); - _target = target; - _normalizer = normalizer; - } - - - public bool Handle(SyncDelta delta) - { - SyncDelta normalized = _normalizer.NormalizeSyncDelta(delta); - return _target(normalized); - } - } - #endregion - - #region ObjectNormalizerFacade - public sealed class ObjectNormalizerFacade - { - /// - /// The (non-null) object class - /// - private readonly ObjectClass _objectClass; - /// - /// The (possibly null) attribute normalizer - /// - private readonly AttributeNormalizer _normalizer; - - /// - /// Create a new ObjectNormalizer - /// - /// The object class - /// The normalizer. May be null. - public ObjectNormalizerFacade(ObjectClass objectClass, - AttributeNormalizer normalizer) - { - Assertions.NullCheck(objectClass, "objectClass"); - _objectClass = objectClass; - _normalizer = normalizer; - } - - /// - /// Returns the normalized value of the attribute. - /// - /// - /// If no normalizer is specified, returns the original - /// attribute. - /// - /// The attribute to normalize. - /// The normalized attribute - public ConnectorAttribute NormalizeAttribute(ConnectorAttribute attribute) - { - if (attribute == null) - { - return null; - } - else if (_normalizer != null) - { - return _normalizer.NormalizeAttribute(_objectClass, attribute); - } - else - { - return attribute; - } - } - - /// - /// Returns the normalized set of attributes or null - /// if the original set is null. - /// - /// The original attributes. - /// The normalized attributes or null if - /// the original set is null. - public ICollection NormalizeAttributes(ICollection attributes) - { - if (attributes == null) - { - return null; - } - ICollection temp = new HashSet(); - foreach (ConnectorAttribute attribute in attributes) - { - temp.Add(NormalizeAttribute(attribute)); - } - return CollectionUtil.AsReadOnlySet(temp); - } - - /// - /// Returns the normalized object. - /// - /// The original object - /// The normalized object. - public ConnectorObject NormalizeObject(ConnectorObject orig) - { - return new ConnectorObject(orig.ObjectClass, - NormalizeAttributes(orig.GetAttributes())); - } - - /// - /// Returns the normalized sync delta. - /// - /// The original delta. - /// The normalized delta. - public SyncDelta NormalizeSyncDelta(SyncDelta delta) - { - SyncDeltaBuilder builder = new - SyncDeltaBuilder(delta); - if (delta.Object != null) - { - builder.Object = NormalizeObject(delta.Object); - } - return builder.Build(); - } - - /// - /// Returns a filter consisting of the original with - /// all attributes normalized. - /// - /// The original. - /// The normalized filter. - public Filter NormalizeFilter(Filter filter) - { - if (filter is ContainsFilter) - { - AttributeFilter afilter = - (AttributeFilter)filter; - return new ContainsFilter(NormalizeAttribute(afilter.GetAttribute())); - } - else if (filter is EndsWithFilter) - { - AttributeFilter afilter = - (AttributeFilter)filter; - return new EndsWithFilter(NormalizeAttribute(afilter.GetAttribute())); - } - else if (filter is EqualsFilter) - { - AttributeFilter afilter = - (AttributeFilter)filter; - return new EqualsFilter(NormalizeAttribute(afilter.GetAttribute())); - } - else if (filter is GreaterThanFilter) - { - AttributeFilter afilter = - (AttributeFilter)filter; - return new GreaterThanFilter(NormalizeAttribute(afilter.GetAttribute())); - } - else if (filter is GreaterThanOrEqualFilter) - { - AttributeFilter afilter = - (AttributeFilter)filter; - return new GreaterThanOrEqualFilter(NormalizeAttribute(afilter.GetAttribute())); - } - else if (filter is LessThanFilter) - { - AttributeFilter afilter = - (AttributeFilter)filter; - return new LessThanFilter(NormalizeAttribute(afilter.GetAttribute())); - } - else if (filter is LessThanOrEqualFilter) - { - AttributeFilter afilter = - (AttributeFilter)filter; - return new LessThanOrEqualFilter(NormalizeAttribute(afilter.GetAttribute())); - } - else if (filter is StartsWithFilter) - { - AttributeFilter afilter = - (AttributeFilter)filter; - return new StartsWithFilter(NormalizeAttribute(afilter.GetAttribute())); - } - else if (filter is ContainsAllValuesFilter) - { - AttributeFilter afilter = - (AttributeFilter)filter; - return new ContainsAllValuesFilter(NormalizeAttribute(afilter.GetAttribute())); - } - else if (filter is NotFilter) - { - NotFilter notFilter = - (NotFilter)filter; - return new NotFilter(NormalizeFilter(notFilter.Filter)); - } - else if (filter is AndFilter) - { - AndFilter andFilter = - (AndFilter)filter; - return new AndFilter(NormalizeFilter(andFilter.Left), - NormalizeFilter(andFilter.Right)); - } - else if (filter is OrFilter) - { - OrFilter orFilter = - (OrFilter)filter; - return new OrFilter(NormalizeFilter(orFilter.Left), - NormalizeFilter(orFilter.Right)); - } - else - { - return filter; - } - } - } - #endregion - - #region SchemaImpl - internal class SchemaImpl : ConnectorAPIOperationRunner, SchemaApiOp - { - /// - /// Initializes the operation works. - /// - public SchemaImpl(ConnectorOperationalContext context, - Connector connector) - : base(context, connector) - { - } - - /// - /// Retrieve the schema from the . - /// - /// - public Schema Schema() - { - return ((SchemaOp)GetConnector()).Schema(); - } - } - #endregion - - #region ScriptOnConnectorImpl - public class ScriptOnConnectorImpl : ConnectorAPIOperationRunner, - ScriptOnConnectorApiOp - { - public ScriptOnConnectorImpl(ConnectorOperationalContext context, - Connector connector) : - base(context, connector) - { - } - - public Object RunScriptOnConnector(ScriptContext request, - OperationOptions options) - { - Assertions.NullCheck(request, "request"); - //convert null into empty - if (options == null) - { - options = new OperationOptionsBuilder().Build(); - } - Object rv; - if (GetConnector() is ScriptOnConnectorOp) - { - rv = ((ScriptOnConnectorOp)GetConnector()).RunScriptOnConnector(request, options); - } - else - { - String language = request.ScriptLanguage; - Assembly assembly = GetConnector().GetType().Assembly; - - ScriptExecutor executor = - ScriptExecutorFactory.NewInstance(language).NewScriptExecutor( - BuildReferenceList(assembly), - request.ScriptText, - false); - IDictionary scriptArgs = - new Dictionary(request.ScriptArguments); - scriptArgs["connector"] = GetConnector(); //add the connector instance itself - rv = executor.Execute(scriptArgs); - } - return SerializerUtil.CloneObject(rv); - } - - private Assembly[] BuildReferenceList(Assembly assembly) - { - List list = new List(); - BuildReferenceList2(assembly, list, new HashSet()); - return list.ToArray(); - } - - private void BuildReferenceList2(Assembly assembly, - List list, - HashSet visited) - { - bool notThere = visited.Add(assembly.GetName().FullName); - if (notThere) - { - list.Add(assembly); - foreach (AssemblyName referenced in assembly.GetReferencedAssemblies()) - { - Assembly assembly2 = Assembly.Load(referenced); - BuildReferenceList2(assembly2, list, visited); - } - } - } - } - #endregion - - #region ScriptOnResourceImpl - public class ScriptOnResourceImpl : ConnectorAPIOperationRunner, - ScriptOnResourceApiOp - { - public ScriptOnResourceImpl(ConnectorOperationalContext context, - Connector connector) : - base(context, connector) - { - } - - public Object RunScriptOnResource(ScriptContext request, - OperationOptions options) - { - Assertions.NullCheck(request, "request"); - //convert null into empty - if (options == null) - { - options = new OperationOptionsBuilder().Build(); - } - Object rv - = ((ScriptOnResourceOp)GetConnector()).RunScriptOnResource(request, options); - return SerializerUtil.CloneObject(rv); - } - - } - #endregion - - #region SearchImpl - internal class SearchImpl : ConnectorAPIOperationRunner, SearchApiOp - { - /// - /// Initializes the operation works. - /// - public SearchImpl(ConnectorOperationalContext context, - Connector connector) - : base(context, connector) - { - } - - /// - /// Call the SPI search routines to return the results to the - /// . - /// - /// - public void Search(ObjectClass oclass, Filter originalFilter, ResultsHandler handler, OperationOptions options) - { - Assertions.NullCheck(oclass, "oclass"); - Assertions.NullCheck(handler, "handler"); - //convert null into empty - if (options == null) - { - options = new OperationOptionsBuilder().Build(); - } - ObjectNormalizerFacade normalizer = - GetNormalizer(oclass); - //chain a normalizing handler (must come before - //filter handler) - handler = - new NormalizingResultsHandler(handler, normalizer).Handle; - Filter normalizedFilter = - normalizer.NormalizeFilter(originalFilter); - - //get the IList interface that this type implements - Type interfaceType = ReflectionUtil.FindInHierarchyOf - (typeof(SearchOp<>), GetConnector().GetType()); - Type[] val = interfaceType.GetGenericArguments(); - if (val.Length != 1) - { - throw new Exception("Unexpected type: " + interfaceType); - } - Type queryType = val[0]; - Type searcherRawType = typeof(RawSearcherImpl<>); - Type searcherType = - searcherRawType.MakeGenericType(queryType); - RawSearcher searcher = (RawSearcher)Activator.CreateInstance(searcherType); - // add filtering handler - handler = new FilteredResultsHandler(handler, normalizedFilter).Handle; - // add attributes to get handler - string[] attrsToGet = options.AttributesToGet; - if (attrsToGet != null && attrsToGet.Length > 0) - { - handler = new SearchAttributesToGetResultsHandler( - handler, attrsToGet).Handle; - } - searcher.RawSearch(GetConnector(), oclass, normalizedFilter, handler, options); - } - } - #endregion - - #region RawSearcher - internal interface RawSearcher - { - /// - /// Public because it is used by TestHelpers. - /// - /// - /// Raw, - /// SPI-level search. - /// - /// The underlying implementation of search - /// (generally the connector itself) - /// The object class - /// The filter - /// The handler - /// The options - void RawSearch(Object search, - ObjectClass oclass, - Filter filter, - ResultsHandler handler, - OperationOptions options); - } - #endregion - - #region RawSearcherImpl - internal class RawSearcherImpl : RawSearcher where T : class - { - public void RawSearch(Object search, - ObjectClass oclass, - Filter filter, - ResultsHandler handler, - OperationOptions options) - { - RawSearch((SearchOp)search, oclass, filter, handler, options); - } - - /// - /// Public because it is used by TestHelpers. - /// - /// - /// Raw, - /// SPI-level search. - /// - /// The underlying implementation of search - /// (generally the connector itself) - /// The object class - /// The filter - /// The handler - /// The options - public static void RawSearch(SearchOp search, - ObjectClass oclass, - Filter filter, - ResultsHandler handler, - OperationOptions options) - { - - FilterTranslator translator = - search.CreateFilterTranslator(oclass, options); - IList queries = - (IList)translator.Translate(filter); - if (queries.Count == 0) - { - search.ExecuteQuery(oclass, - null, handler, options); - } - else - { - //eliminate dups if more than one - bool eliminateDups = - queries.Count > 1; - DuplicateFilteringResultsHandler dups = null; - if (eliminateDups) - { - dups = new DuplicateFilteringResultsHandler(handler); - handler = dups.Handle; - } - foreach (T query in queries) - { - search.ExecuteQuery(oclass, - query, handler, options); - //don't run any more queries if the consumer - //has stopped - if (dups != null) - { - if (!dups.IsStillHandling) - { - break; - } - } - } - } - } - - } - #endregion - - #region SyncImpl - public class SyncImpl : ConnectorAPIOperationRunner, - SyncApiOp - { - public SyncImpl(ConnectorOperationalContext context, - Connector connector) - : base(context, connector) - { - } - - public void Sync(ObjectClass objClass, SyncToken token, - SyncResultsHandler handler, - OperationOptions options) - { - //token is allowed to be null, objClass and handler must not be null - Assertions.NullCheck(objClass, "objClass"); - Assertions.NullCheck(handler, "handler"); - //convert null into empty - if (options == null) - { - options = new OperationOptionsBuilder().Build(); - } - // add a handler in the chain to remove attributes - string[] attrsToGet = options.AttributesToGet; - if (attrsToGet != null && attrsToGet.Length > 0) - { - handler = new SyncAttributesToGetResultsHandler( - handler, attrsToGet).Handle; - } - //chain a normalizing results handler - ObjectNormalizerFacade normalizer = - GetNormalizer(objClass); - handler = new NormalizingSyncResultsHandler(handler, normalizer).Handle; - ((SyncOp)GetConnector()).Sync(objClass, token, handler, options); - } - public SyncToken GetLatestSyncToken(ObjectClass objectClass) - { - return ((SyncOp)GetConnector()).GetLatestSyncToken(objectClass); - } - } - #endregion - - #region TestImpl - /// - /// Provides a method for the API to call the SPI's test method on the - /// connector. - /// - /// - /// The test method is intended to determine if the - /// is ready to perform the various operations it supports. - /// - /// Will Droste - internal class TestImpl : ConnectorAPIOperationRunner, TestApiOp - { - public TestImpl(ConnectorOperationalContext context, Connector connector) - : base(context, connector) - { - } - - public void Test() - { - ((TestOp)GetConnector()).Test(); - } - - } - #endregion - - #region UpdateImpl - /// - /// NOTE: internal class, public only for unit tests - /// Handles both version of update this include simple replace and the advance - /// update. - /// - public class UpdateImpl : ConnectorAPIOperationRunner, UpdateApiOp - { - /// - /// All the operational attributes that can not be added or deleted. - /// - static readonly HashSet OPERATIONAL_ATTRIBUTE_NAMES = new HashSet(); - - const String OPERATIONAL_ATTRIBUTE_ERR = - "Operational attribute '{0}' can not be added or deleted only replaced."; - - static UpdateImpl() - { - OPERATIONAL_ATTRIBUTE_NAMES.Add(Name.NAME); - CollectionUtil.AddAll(OPERATIONAL_ATTRIBUTE_NAMES, - OperationalAttributes.OPERATIONAL_ATTRIBUTE_NAMES); - } - - /// - /// Determines which type of update a connector supports and then uses that - /// handler. - /// - public UpdateImpl(ConnectorOperationalContext context, - Connector connector) - : base(context, connector) - { - } - - public Uid Update(ObjectClass objclass, - Uid uid, - ICollection replaceAttributes, - OperationOptions options) - { - // validate all the parameters.. - ValidateInput(objclass, uid, replaceAttributes, false); - //cast null as empty - if (options == null) - { - options = new OperationOptionsBuilder().Build(); - } - - ObjectNormalizerFacade normalizer = - GetNormalizer(objclass); - uid = (Uid)normalizer.NormalizeAttribute(uid); - replaceAttributes = - normalizer.NormalizeAttributes(replaceAttributes); - UpdateOp op = (UpdateOp)GetConnector(); - Uid ret = op.Update(objclass, uid, replaceAttributes, options); - return (Uid)normalizer.NormalizeAttribute(ret); - } - - public Uid AddAttributeValues(ObjectClass objclass, - Uid uid, - ICollection valuesToAdd, - OperationOptions options) - { - // validate all the parameters.. - ValidateInput(objclass, uid, valuesToAdd, true); - //cast null as empty - if (options == null) - { - options = new OperationOptionsBuilder().Build(); - } - - ObjectNormalizerFacade normalizer = - GetNormalizer(objclass); - uid = (Uid)normalizer.NormalizeAttribute(uid); - valuesToAdd = - normalizer.NormalizeAttributes(valuesToAdd); - UpdateOp op = (UpdateOp)GetConnector(); - Uid ret; - if (op is UpdateAttributeValuesOp) - { - UpdateAttributeValuesOp valueOp = - (UpdateAttributeValuesOp)op; - ret = valueOp.AddAttributeValues(objclass, uid, valuesToAdd, options); - } - else - { - ICollection replaceAttributes = - FetchAndMerge(objclass, uid, valuesToAdd, true, options); - ret = op.Update(objclass, uid, replaceAttributes, options); - } - return (Uid)normalizer.NormalizeAttribute(ret); - } - - public Uid RemoveAttributeValues(ObjectClass objclass, - Uid uid, - ICollection valuesToRemove, - OperationOptions options) - { - // validate all the parameters.. - ValidateInput(objclass, uid, valuesToRemove, true); - //cast null as empty - if (options == null) - { - options = new OperationOptionsBuilder().Build(); - } - - ObjectNormalizerFacade normalizer = - GetNormalizer(objclass); - uid = (Uid)normalizer.NormalizeAttribute(uid); - valuesToRemove = - normalizer.NormalizeAttributes(valuesToRemove); - UpdateOp op = (UpdateOp)GetConnector(); - Uid ret; - if (op is UpdateAttributeValuesOp) - { - UpdateAttributeValuesOp valueOp = - (UpdateAttributeValuesOp)op; - ret = valueOp.RemoveAttributeValues(objclass, uid, valuesToRemove, options); - } - else - { - ICollection replaceAttributes = - FetchAndMerge(objclass, uid, valuesToRemove, false, options); - ret = op.Update(objclass, uid, replaceAttributes, options); - } - return (Uid)normalizer.NormalizeAttribute(ret); - } - - private ICollection FetchAndMerge(ObjectClass objclass, Uid uid, - ICollection valuesToChange, - bool add, - OperationOptions options) - { - // check that this connector supports Search.. - if (ReflectionUtil.FindInHierarchyOf(typeof(SearchOp<>), GetConnector().GetType()) == null) - { - String MSG = "Connector must support search"; - throw new InvalidOperationException(MSG); - } - - //add attrs to get to operation options, so that the - //object we fetch has exactly the set of attributes we require - //(there may be ones that are not in the default set) - OperationOptionsBuilder builder = new OperationOptionsBuilder(options); - ICollection attrNames = new HashSet(); - foreach (ConnectorAttribute attribute in valuesToChange) - { - attrNames.Add(attribute.Name); - } - builder.AttributesToGet = (attrNames.ToArray()); - options = builder.Build(); - - // get the connector object from the resource... - ConnectorObject o = GetConnectorObject(objclass, uid, options); - if (o == null) - { - throw new UnknownUidException(uid, objclass); - } - // merge the update data.. - ICollection mergeAttrs = Merge(valuesToChange, o.GetAttributes(), add); - return mergeAttrs; - } - - /// - /// Merges two connector objects into a single updated object. - /// - public ICollection Merge(ICollection updateAttrs, - ICollection baseAttrs, bool add) - { - // return the merged attributes - ICollection ret = new HashSet(); - // create map that can be modified to get the subset of changes - IDictionary baseAttrMap = ConnectorAttributeUtil.ToMap(baseAttrs); - // run through attributes of the current object.. - foreach (ConnectorAttribute updateAttr in updateAttrs) - { - // get the name of the update attributes - String name = updateAttr.Name; - // remove each attribute that is an update attribute.. - ConnectorAttribute baseAttr = CollectionUtil.GetValue(baseAttrMap, name, null); - IList values; - ConnectorAttribute modifiedAttr; - if (add) - { - if (baseAttr == null) - { - modifiedAttr = updateAttr; - } - else - { - // create a new list with the base attribute to add to.. - values = CollectionUtil.NewList(baseAttr.Value); - CollectionUtil.AddAll(values, updateAttr.Value); - modifiedAttr = ConnectorAttributeBuilder.Build(name, values); - } - } - else - { - if (baseAttr == null) - { - // nothing to actually do the attribute do not exist - continue; - } - else - { - // create a list with the base attribute to remove from.. - values = CollectionUtil.NewList(baseAttr.Value); - foreach (Object val in updateAttr.Value) - { - values.Remove(val); - } - // if the values are empty send a null to the connector.. - if (values.Count == 0) - { - modifiedAttr = ConnectorAttributeBuilder.Build(name); - } - else - { - modifiedAttr = ConnectorAttributeBuilder.Build(name, values); - } - } - } - ret.Add(modifiedAttr); - } - return ret; - } - - /// - /// Get the to modify. - /// - private ConnectorObject GetConnectorObject(ObjectClass oclass, Uid uid, OperationOptions options) - { - // attempt to get the connector object.. - GetApiOp get = new GetImpl(new SearchImpl((ConnectorOperationalContext)GetOperationalContext(), - GetConnector())); - return get.GetObject(oclass, uid, options); - } - - /// - /// Makes things easier if you can trust the input. - /// - public static void ValidateInput(ObjectClass objclass, - Uid uid, - ICollection attrs, bool isDelta) - { - Assertions.NullCheck(uid, "uid"); - Assertions.NullCheck(objclass, "objclass"); - Assertions.NullCheck(attrs, "attrs"); - // check to make sure there's not a uid.. - if (ConnectorAttributeUtil.GetUidAttribute(attrs) != null) - { - throw new ArgumentException( - "Parameter 'attrs' contains a uid."); - } - // check for things only valid during ADD/DELETE - if (isDelta) - { - foreach (ConnectorAttribute attr in attrs) - { - Assertions.NullCheck(attr, "attr"); - // make sure that none of the values are null.. - if (attr.Value == null) - { - throw new ArgumentException( - "Can not add or remove a 'null' value."); - } - // make sure that if this an delete/add that it doesn't include - // certain attributes because it doesn't make any sense.. - String name = attr.Name; - if (OPERATIONAL_ATTRIBUTE_NAMES.Contains(name)) - { - String msg = String.Format(OPERATIONAL_ATTRIBUTE_ERR, name); - throw new ArgumentException(msg); - } - } - } - } - } - #endregion - - #region ValidateImpl - internal class ValidateImpl : APIOperationRunner, ValidateApiOp - { - - public ValidateImpl(OperationalContext context) - : base(context) - { - } - - public void Validate() - { - GetOperationalContext().GetConfiguration().Validate(); - } - } - #endregion -} \ No newline at end of file diff --git a/FrameworkInternal/ApiRemote.cs b/FrameworkInternal/ApiRemote.cs deleted file mode 100644 index a4a0b7d..0000000 --- a/FrameworkInternal/ApiRemote.cs +++ /dev/null @@ -1,428 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.IO; -using System.Net; -using System.Reflection; -using System.Security.Authentication; -using System.Globalization; -using System.Net.Security; -using System.Net.Sockets; -using System.Security.Cryptography.X509Certificates; -using System.Threading; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Common.Proxy; -using Org.IdentityConnectors.Framework.Api; -using Org.IdentityConnectors.Framework.Api.Operations; -using Org.IdentityConnectors.Framework.Common.Exceptions; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Common.Objects.Filters; -using Org.IdentityConnectors.Framework.Common.Serializer; -using Org.IdentityConnectors.Framework.Impl.Api; -using Org.IdentityConnectors.Framework.Impl.Api.Local.Operations; -using Org.IdentityConnectors.Framework.Impl.Api.Remote.Messages; -using System.Diagnostics; -namespace Org.IdentityConnectors.Framework.Impl.Api.Remote -{ - public class RemoteFrameworkConnection : IDisposable - { - private TcpClient _socket; - private Stream _stream; - - private BinaryObjectSerializer _encoder; - private BinaryObjectDeserializer _decoder; - - public RemoteFrameworkConnection(RemoteFrameworkConnectionInfo info) - { - Init(info); - } - - public RemoteFrameworkConnection(TcpClient socket, Stream stream) - { - Init(socket, stream); - } - - private void Init(RemoteFrameworkConnectionInfo connectionInfo) - { - IPAddress[] addresses = - Dns.GetHostAddresses(connectionInfo.Host); - TcpClient client = new TcpClient(addresses[0].AddressFamily); - client.SendTimeout = connectionInfo.Timeout; - client.ReceiveTimeout = connectionInfo.Timeout; - client.Connect(addresses[0], connectionInfo.Port); - Stream stream; - try - { - stream = client.GetStream(); - } - catch (Exception) - { - try { client.Close(); } - catch (Exception) { } - throw; - } - try - { - if (connectionInfo.UseSSL) - { - if (connectionInfo.CertificateValidationCallback != null) - { - RemoteCertificateValidationCallback callback = - connectionInfo.CertificateValidationCallback; - - stream = new SslStream( - stream, false, callback); - } - else - { - stream = new SslStream(stream, - false); - } - ((SslStream)stream).AuthenticateAsClient(connectionInfo.Host, - new X509CertificateCollection(new X509Certificate[0]), - SslProtocols.Tls, - false); - } - } - catch (Exception) - { - try { stream.Close(); } - catch (Exception) { } - try { client.Close(); } - catch (Exception) { } - throw; - } - Init(client, stream); - } - - private void Init(TcpClient socket, Stream stream) - { - _socket = socket; - _stream = stream; - ObjectSerializerFactory fact = - ObjectSerializerFactory.GetInstance(); - _encoder = fact.NewBinarySerializer(_stream); - _decoder = fact.NewBinaryDeserializer(_stream); - } - - public void Dispose() - { - Flush(); - _stream.Close(); - _socket.Close(); - } - - public void Flush() - { - _encoder.Flush(); - } - - public void WriteObject(object obj) - { - _encoder.WriteObject(obj); - } - - public object ReadObject() - { - //flush first in case there is any data in the - //output buffer - Flush(); - return _decoder.ReadObject(); - } - } - - /// - /// internal class, public only for unit tests - /// - public sealed class RemoteConnectorInfoImpl : AbstractConnectorInfo - { - - - public RemoteConnectorInfoImpl() - { - - } - - //transient field, not serialized - public RemoteFrameworkConnectionInfo RemoteConnectionInfo { get; set; } - - } - - public class RemoteConnectorInfoManagerImpl : ConnectorInfoManager - { - private IList _connectorInfo; - - private RemoteConnectorInfoManagerImpl() - { - - } - - public RemoteConnectorInfoManagerImpl(RemoteFrameworkConnectionInfo info) - { - using (RemoteFrameworkConnection connection = - new RemoteFrameworkConnection(info)) - { - connection.WriteObject(CultureInfo.CurrentUICulture); - connection.WriteObject(info.Key); - connection.WriteObject(new HelloRequest()); - HelloResponse response = (HelloResponse)connection.ReadObject(); - if (response.Exception != null) - { - throw response.Exception; - } - IList remoteInfos = - response.ConnectorInfos; - //populate transient fields not serialized - foreach (RemoteConnectorInfoImpl remoteInfo in remoteInfos) - { - remoteInfo.RemoteConnectionInfo = info; - } - _connectorInfo = - CollectionUtil.NewReadOnlyList(remoteInfos); - } - - } - - /// - /// Derives another RemoteConnectorInfoManagerImpl with - /// a different RemoteFrameworkConnectionInfo but with the - /// same metadata - /// - /// - public RemoteConnectorInfoManagerImpl Derive(RemoteFrameworkConnectionInfo info) - { - RemoteConnectorInfoManagerImpl rv = new RemoteConnectorInfoManagerImpl(); - IList remoteInfosObj = - (IList)SerializerUtil.CloneObject(_connectorInfo); - IList remoteInfos = - CollectionUtil.NewList(remoteInfosObj); - foreach (ConnectorInfo remoteInfo in remoteInfos) - { - ((RemoteConnectorInfoImpl)remoteInfo).RemoteConnectionInfo = (info); - } - rv._connectorInfo = - CollectionUtil.AsReadOnlyList(remoteInfos); - return rv; - } - - public ConnectorInfo FindConnectorInfo(ConnectorKey key) - { - foreach (ConnectorInfo info in _connectorInfo) - { - if (info.ConnectorKey.Equals(key)) - { - return info; - } - } - return null; - } - - public IList ConnectorInfos - { - get - { - return _connectorInfo; - } - } - } - - internal class RemoteConnectorFacadeImpl : AbstractConnectorFacade - { - /// - /// Builds up the maps of supported operations and calls. - /// - public RemoteConnectorFacadeImpl(APIConfigurationImpl configuration) - : base(configuration) - { - } - - protected override APIOperation GetOperationImplementation(SafeType api) - { - InvocationHandler handler = new RemoteOperationInvocationHandler( - GetAPIConfiguration(), - api); - APIOperation proxy = NewAPIOperationProxy(api, handler); - // add logging.. - proxy = CreateLoggingProxy(api, proxy); - return proxy; - } - } - - /// - /// Invocation handler for all of our operations - /// - public class RemoteOperationInvocationHandler : InvocationHandler - { - private readonly APIConfigurationImpl _configuration; - private readonly SafeType _operation; - - public RemoteOperationInvocationHandler(APIConfigurationImpl configuration, - SafeType operation) - { - _configuration = configuration; - _operation = operation; - } - - - public Object Invoke(Object proxy, MethodInfo method, Object[] args) - { - //don't proxy toString, hashCode, or equals - if (method.DeclaringType.Equals(typeof(object))) - { - return method.Invoke(this, args); - } - - //partition arguments into arguments that can - //be simply marshalled as part of the request and - //those that are response handlers - IList simpleMarshallArgs = - CollectionUtil.NewList(args); - ObjectStreamHandler streamHandlerArg = - ExtractStreamHandler(ReflectionUtil.GetParameterTypes(method), simpleMarshallArgs); - - //build the request object - RemoteConnectorInfoImpl connectorInfo = - (RemoteConnectorInfoImpl)_configuration.ConnectorInfo; - RemoteFrameworkConnectionInfo connectionInfo = - connectorInfo.RemoteConnectionInfo; - OperationRequest request = new OperationRequest( - connectorInfo.ConnectorKey, - _configuration, - _operation, - method.Name, - simpleMarshallArgs); - - //create the connection - RemoteFrameworkConnection connection = - new RemoteFrameworkConnection(connectionInfo); - try - { - connection.WriteObject(CultureInfo.CurrentUICulture); - connection.WriteObject(connectionInfo.Key); - //send the request - connection.WriteObject(request); - - //now process each response stream (if any) - if (streamHandlerArg != null) - { - HandleStreamResponse(connection, streamHandlerArg); - } - - //finally return the actual return value - OperationResponsePart response = - (OperationResponsePart)connection.ReadObject(); - if (response.Exception != null) - { - throw response.Exception; - } - return response.Result; - } - finally - { - connection.Dispose(); - } - } - /// - /// Handles a stream response until the end of the stream - /// - private static void HandleStreamResponse(RemoteFrameworkConnection connection, ObjectStreamHandler streamHandler) - { - Object response; - bool handleMore = true; - while (true) - { - response = connection.ReadObject(); - if (response is OperationResponsePart) - { - OperationResponsePart part = (OperationResponsePart)response; - if (part.Exception != null) - { - throw part.Exception; - } - object obj = - part.Result; - if (handleMore) - { - handleMore = streamHandler.Handle(obj); - } - } - else if (response is OperationResponsePause) - { - if (handleMore) - { - connection.WriteObject(new OperationRequestMoreData()); - } - else - { - connection.WriteObject(new OperationRequestStopData()); - } - } - else if (response is OperationResponseEnd) - { - break; - } - else - { - throw new ConnectorException("Unexpected response: " + response); - } - } - } - - /// - /// Partitions arguments into regular arguments and - /// stream arguments. - /// - /// The param types of the method - /// The passed-in arguments. As a - /// side-effect will be set to just the regular arguments. - /// The stream handler arguments. - private static ObjectStreamHandler ExtractStreamHandler(Type[] paramTypes, - IList arguments) - { - ObjectStreamHandler rv = null; - IList filteredArguments = new List(); - for (int i = 0; i < paramTypes.Length; i++) - { - Type paramType = paramTypes[i]; - object arg = arguments[i]; - if (StreamHandlerUtil.IsAdaptableToObjectStreamHandler(paramType)) - { - ObjectStreamHandler handler = StreamHandlerUtil.AdaptToObjectStreamHandler(paramType, arg); - if (rv != null) - { - throw new InvalidOperationException("Multiple stream handlers not supported"); - } - rv = handler; - } - else - { - filteredArguments.Add(arg); - } - } - arguments.Clear(); - CollectionUtil.AddAll(arguments, filteredArguments); - return rv; - } - } -} \ No newline at end of file diff --git a/FrameworkInternal/ApiRemoteMessages.cs b/FrameworkInternal/ApiRemoteMessages.cs deleted file mode 100644 index 4aaf4cf..0000000 --- a/FrameworkInternal/ApiRemoteMessages.cs +++ /dev/null @@ -1,276 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Framework.Api; -using Org.IdentityConnectors.Framework.Api.Operations; -namespace Org.IdentityConnectors.Framework.Impl.Api.Remote.Messages -{ - /// - /// internal class, public only for unit tests - /// - public class HelloRequest : Message - { - - public HelloRequest() - { - } - } - - /// - /// internal class, public only for unit tests - /// - public class HelloResponse : Message - { - /// - /// The exception - /// - private Exception _exception; - - /// - /// List of connector infos, containing infos for all the connectors - /// on the server. - /// - private IList _connectorInfos; - - public HelloResponse(Exception exception, - IList connectorInfos) - { - _exception = exception; - _connectorInfos = CollectionUtil.NewReadOnlyList(connectorInfos); - } - - public Exception Exception - { - get - { - return _exception; - } - } - - public IList ConnectorInfos - { - get - { - return _connectorInfos; - } - } - } - - /// - /// internal class, public only for unit tests - /// - public interface Message - { - } - - /// - /// internal class, public only for unit tests - /// - public class OperationRequest : Message - { - /// - /// The key of the connector to operate on. - /// - private readonly ConnectorKey _connectorKey; - - /// - /// The configuration information to use. - /// - private readonly APIConfigurationImpl _configuration; - - /// - /// The operation to perform. - /// - private readonly SafeType _operation; - - /// - /// The name of the method since operations can have more - /// than one method. - /// - /// - /// NOTE: this is case-insensitive - /// - private readonly String _operationMethodName; - - /// - /// The arguments to the operation. - /// - /// - /// In general, these correspond - /// to the actual arguments of the method. The one exception is - /// search - in this case, the callback is not passed. - /// - private readonly IList _arguments; - - public OperationRequest(ConnectorKey key, - APIConfigurationImpl apiConfiguration, - SafeType operation, - string operationMethodName, - IList arguments) - { - _connectorKey = key; - _configuration = apiConfiguration; - _operation = operation; - _operationMethodName = operationMethodName; - _arguments = CollectionUtil.NewReadOnlyList(arguments); - } - - public ConnectorKey ConnectorKey - { - get - { - return _connectorKey; - } - } - - public APIConfigurationImpl Configuration - { - get - { - return _configuration; - } - } - - public SafeType Operation - { - get - { - return _operation; - } - } - - public string OperationMethodName - { - get - { - return _operationMethodName; - } - } - - public IList Arguments - { - get - { - return _arguments; - } - } - } - - /// - /// internal class, public only for unit tests - /// - public class OperationRequestMoreData : Message - { - public OperationRequestMoreData() - { - } - } - - /// - /// internal class, public only for unit tests - /// - public class OperationRequestStopData : Message - { - public OperationRequestStopData() - { - } - } - - /// - /// internal class, public only for unit tests - /// - public class OperationResponseEnd : Message - { - public OperationResponseEnd() - { - } - } - - /// - /// internal class, public only for unit tests - /// - public class OperationResponsePart : Message - { - private Exception _exception; - private Object _result; - - public OperationResponsePart(Exception ex, Object result) - { - _exception = ex; - _result = result; - } - - public Exception Exception - { - get - { - return _exception; - } - } - - public Object Result - { - get - { - return _result; - } - } - } - - /// - /// internal class, public only for unit tests - /// - public class OperationResponsePause : Message - { - public OperationResponsePause() - { - } - } - - public class EchoMessage : Message - { - private object _object; - private string _objectXml; - public EchoMessage(object obj, string xml) - { - _object = obj; - _objectXml = xml; - } - public object Object - { - get - { - return _object; - } - } - public string ObjectXml - { - get - { - return _objectXml; - } - } - } -} \ No newline at end of file diff --git a/FrameworkInternal/ExceptionUtil.cs b/FrameworkInternal/ExceptionUtil.cs deleted file mode 100644 index 4b06af7..0000000 --- a/FrameworkInternal/ExceptionUtil.cs +++ /dev/null @@ -1,87 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Linq; -using System.Text; -using System.Reflection; -using System.Diagnostics; -using Org.IdentityConnectors.Common; -using System.Runtime.CompilerServices; - -namespace Org.IdentityConnectors.Framework.Impl -{ - /// - /// Contains utilities to handle exceptions. - /// - public static class ExceptionUtil - { - private const string PreserveStackTraceMethodName = "InternalPreserveStackTrace"; - - /// - /// Preserves the stack trace of . - /// - /// The exception, the stack trace of which to be preserved. - /// In the .Net Framework the stack trace of an exception starts to get populated when it is thrown, - /// hence if an exception is re-thrown by a method upper in the call chain the stack trace will reflect that the - /// exception occurred at that position where the exception was actually re-thrown and the original stack trace will - /// be lost. - /// - /// - /// try - /// { - /// function_that_throws_an_exception_with_a_nested_one(); - /// } - /// catch( Exception ex ) - /// { - /// throw ex.InnerException; //clears the stack trace of the nested exception - /// } - /// - /// - /// There is no built-in support in .Net to preserve the stack trace, however, an internal method - /// of the class called - /// can be used to achieve this. Since it is an internal method it might be subject to change, therefore if it is - /// not possible to invoke the method by any reason the error cause will be traced, but it will not break the execution. - /// - public static void PreserveStackTrace(Exception exception) - { - Assertions.NullCheck(exception, "exception"); - - try - { - MethodInfo preserveStackTrace = typeof(Exception).GetMethod( - PreserveStackTraceMethodName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod); - - preserveStackTrace.Invoke(exception, null); - } - catch (Exception ex) - { - //it should not ever happen, but we have to make sure that if a next release of .Net Framework does not - //include the invoked method it will not break the execution - TraceUtil.TraceException(string.Format( - @"Could not set an exception to preserve its stack trace. Exception: ""{0}""", exception), ex); - return; - } - } - } -} \ No newline at end of file diff --git a/FrameworkInternal/FrameworkInternal.csproj b/FrameworkInternal/FrameworkInternal.csproj deleted file mode 100644 index 7ab7282..0000000 --- a/FrameworkInternal/FrameworkInternal.csproj +++ /dev/null @@ -1,109 +0,0 @@ - - - - {5B011775-B121-4EEE-A410-BA2D2F5BFB8B} - Debug - AnyCPU - Library - Org.IdentityConnectors - FrameworkInternal - FrameworkInternal - v3.5 - True - False - 4 - false - - - prompt - 4 - true - bin\Debug\ - Full - False - True - DEBUG;TRACE - - - pdbonly - bin\Release\ - False - prompt - 4 - True - False - TRACE - - - False - Auto - 4194304 - AnyCPU - 4096 - - - - - - - 3.5 - - - - - - - - - - - - - - - - - - - - - - Designer - - - - - {F140E8DA-52B4-4159-992A-9DA10EA8EEFB} - Common - - - {8B24461B-456A-4032-89A1-CD418F7B5B62} - Framework - - - {E6A207D2-E083-41BF-B522-D9D3EC09323E} - TestCommon - - - \ No newline at end of file diff --git a/FrameworkInternal/Resources.resx b/FrameworkInternal/Resources.resx deleted file mode 100644 index c9f2875..0000000 --- a/FrameworkInternal/Resources.resx +++ /dev/null @@ -1,508 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - <?xml version='1.0' encoding='UTF-8'?> - - -<!--=======================================================--> -<!--= =--> -<!--= DTD for Connector Objects =--> -<!--= =--> -<!--=======================================================--> - -<!--=======================================================--> -<!--= =--> -<!--= All XML Objects =--> -<!--= =--> -<!--=======================================================--> - -<!ENTITY % exceptionTypes - "AlreadyExistsException | ConfigurationException | ConnectionBrokenException - | ConnectionFailedException | ConnectorIOException | InvalidPasswordException - | UnknownUidException | InvalidCredentialException | PermissionDeniedException - | ConnectorSecurityException | OperationTimeoutException | ConnectorException - | RuntimeException | Exception | Throwable | PasswordExpiredException | IllegalArgumentException - "> - -<!ENTITY % messageTypes - "HelloRequest | HelloResponse | OperationRequest | OperationResponseEnd | - OperationResponsePart | OperationRequestMoreData | OperationRequestStopData | - OperationResponsePause | EchoMessage - "> - -<!ENTITY % filterTypes - "AndFilter | ContainsFilter | EndsWithFilter | EqualsFilter | - GreaterThanFilter | GreaterThanOrEqualFilter | LessThanFilter | - LessThanOrEqualFilter | NotFilter | OrFilter | StartsWithFilter | - ContainsAllValuesFilter - "> - -<!ENTITY % attributeTypes - "Attribute | Uid | Name"> - -<!ENTITY % primitiveTypes - "null | Array | Boolean | boolean | Character | char | Integer | - int | Long | long | Float | float | Double | double | String | - URI | File | BigDecimal | BigInteger | ByteArray | Class | - Map | List | Set | Locale | GuardedByteArray | GuardedString - "> - -<!ENTITY % xmlObject - "%primitiveTypes; | %exceptionTypes; | %messageTypes; | %filterTypes; | %attributeTypes; | -ObjectPoolConfiguration | ConfigurationProperty | ConfigurationProperties | -APIConfiguration | ConnectorMessages | ConnectorKey | ConnectorInfo | -UpdateApiOpType | AttributeInfo | ConnectorObject | ObjectClass | -ObjectClassInfo | Schema | Script | ScriptContext | OperationOptions | -OperationOptionInfo | SyncDeltaType | SyncToken | SyncDelta | QualifiedUid -"> - - - -<!--=======================================================--> -<!--= =--> -<!--= Top Level Element for object streams =--> -<!--= =--> -<!--=======================================================--> - - -<!ELEMENT MultiObject (( - %xmlObject; -)*)> - - -<!--=======================================================--> -<!--= =--> -<!--= Primitives =--> -<!--= =--> -<!--=======================================================--> - - - -<!ELEMENT null EMPTY> -<!ELEMENT Array ((%xmlObject;)*)> -<!ATTLIST Array - componentType CDATA #REQUIRED -> -<!ELEMENT Boolean (#PCDATA)> -<!ELEMENT boolean (#PCDATA)> -<!ELEMENT Character (#PCDATA)> -<!ELEMENT char (#PCDATA)> -<!ELEMENT Integer (#PCDATA)> -<!ELEMENT int (#PCDATA)> -<!ELEMENT Long (#PCDATA)> -<!ELEMENT long (#PCDATA)> -<!ELEMENT Float (#PCDATA)> -<!ELEMENT float (#PCDATA)> -<!ELEMENT Double (#PCDATA)> -<!ELEMENT double (#PCDATA)> -<!ELEMENT String (#PCDATA)> -<!ELEMENT URI (#PCDATA)> -<!ELEMENT File (#PCDATA)> -<!ELEMENT BigDecimal EMPTY> -<!ATTLIST BigDecimal - unscaled CDATA #REQUIRED - scale CDATA #REQUIRED -> -<!ELEMENT BigInteger (#PCDATA)> -<!ELEMENT ByteArray (#PCDATA)> -<!ELEMENT Class (#PCDATA)> -<!ELEMENT Map ((MapEntry)*)> - -<!ATTLIST Map - caseInsensitive CDATA #IMPLIED -> -<!ELEMENT MapEntry ((%xmlObject;),(%xmlObject;))> -<!ELEMENT Keys ((%xmlObject;)*)> -<!ELEMENT List ((%xmlObject;)*)> -<!ELEMENT Set ((%xmlObject;)*)> -<!ATTLIST Set - caseInsensitive CDATA #IMPLIED -> -<!ELEMENT Locale EMPTY> -<!ATTLIST Locale - language CDATA #IMPLIED - country CDATA #IMPLIED - variant CDATA #IMPLIED -> -<!ELEMENT GuardedByteArray (#PCDATA)> -<!ELEMENT GuardedString (#PCDATA)> - -<!--=======================================================--> -<!--= =--> -<!--= APIConfiguration =--> -<!--= =--> -<!--=======================================================--> - -<!ELEMENT ObjectPoolConfiguration EMPTY> -<!ATTLIST ObjectPoolConfiguration - maxObjects CDATA #IMPLIED - maxIdle CDATA #IMPLIED - maxWait CDATA #IMPLIED - minEvictableIdleTimeMillis CDATA #IMPLIED - minIdle CDATA #IMPLIED -> - -<!ELEMENT ConfigurationProperty (value,operations)> -<!ATTLIST ConfigurationProperty - order CDATA #IMPLIED - confidential CDATA #IMPLIED - required CDATA #IMPLIED - name CDATA #REQUIRED - helpMessageKey CDATA #REQUIRED - displayMessageKey CDATA #REQUIRED - type CDATA #REQUIRED -> -<!ELEMENT value (%xmlObject;)> -<!ELEMENT operations (Class)*> -<!ELEMENT ConfigurationProperties ((ConfigurationProperty)*)> - -<!ELEMENT APIConfiguration (connectorPoolConfiguration,ConfigurationProperties,timeoutMap,SupportedOperations)> -<!ATTLIST APIConfiguration - connectorPoolingSupported CDATA #REQUIRED - producerBufferSize CDATA #REQUIRED -> -<!ELEMENT connectorPoolConfiguration ((ObjectPoolConfiguration))> -<!ELEMENT timeoutMap (Map)> -<!ELEMENT SupportedOperations ((Class)*)> -<!ELEMENT ConnectorMessages (catalogs)> -<!ELEMENT catalogs (Map)> -<!ELEMENT ConnectorKey EMPTY> -<!ATTLIST ConnectorKey - bundleName CDATA #REQUIRED - bundleVersion CDATA #REQUIRED - connectorName CDATA #REQUIRED -> -<!ELEMENT ConnectorInfo (ConnectorKey,ConnectorMessages,APIConfiguration)> -<!ATTLIST ConnectorInfo - connectorDisplayNameKey CDATA #REQUIRED -> - -<!--=======================================================--> -<!--= =--> -<!--= Common Objects =--> -<!--= =--> -<!--=======================================================--> -<!ELEMENT Attribute (Values)?> -<!ELEMENT Values ((%xmlObject;)*)> - -<!ATTLIST Attribute - name CDATA #REQUIRED -> - -<!ELEMENT Uid (#PCDATA)> -<!ELEMENT Name (#PCDATA)> - - - -<!ELEMENT UpdateApiOpType (#PCDATA)> - - -<!ELEMENT AlreadyExistsException EMPTY> -<!ATTLIST AlreadyExistsException - message CDATA #IMPLIED -> -<!ELEMENT ConfigurationException EMPTY> -<!ATTLIST ConfigurationException - message CDATA #IMPLIED -> -<!ELEMENT ConnectionBrokenException EMPTY> -<!ATTLIST ConnectionBrokenException - message CDATA #IMPLIED -> -<!ELEMENT ConnectionFailedException EMPTY> -<!ATTLIST ConnectionFailedException - message CDATA #IMPLIED -> -<!ELEMENT ConnectorIOException EMPTY> -<!ATTLIST ConnectorIOException - message CDATA #IMPLIED -> -<!ELEMENT InvalidPasswordException EMPTY> -<!ATTLIST InvalidPasswordException - message CDATA #IMPLIED -> -<!ELEMENT PasswordExpiredException (Uid?)> -<!ATTLIST PasswordExpiredException - message CDATA #IMPLIED -> -<!ELEMENT UnknownUidException EMPTY> -<!ATTLIST UnknownUidException - message CDATA #IMPLIED -> -<!ELEMENT InvalidCredentialException EMPTY> -<!ATTLIST InvalidCredentialException - message CDATA #IMPLIED -> -<!ELEMENT PermissionDeniedException EMPTY> -<!ATTLIST PermissionDeniedException - message CDATA #IMPLIED -> -<!ELEMENT ConnectorSecurityException EMPTY> -<!ATTLIST ConnectorSecurityException - message CDATA #IMPLIED -> -<!ELEMENT OperationTimeoutException EMPTY> -<!ATTLIST OperationTimeoutException - message CDATA #IMPLIED -> -<!ELEMENT ConnectorException EMPTY> -<!ATTLIST ConnectorException - message CDATA #IMPLIED -> -<!ELEMENT IllegalArgumentException EMPTY> -<!ATTLIST IllegalArgumentException - message CDATA #IMPLIED -> -<!ELEMENT RuntimeException EMPTY> -<!ATTLIST RuntimeException - message CDATA #IMPLIED -> -<!ELEMENT Exception EMPTY> -<!ATTLIST Exception - message CDATA #IMPLIED -> -<!ELEMENT Throwable EMPTY> -<!ATTLIST Throwable - message CDATA #IMPLIED -> -<!ELEMENT AttributeInfo (AttributeInfoFlag*)> -<!ATTLIST AttributeInfo - name CDATA #REQUIRED - type CDATA #REQUIRED -> -<!ELEMENT AttributeInfoFlag EMPTY> -<!ATTLIST AttributeInfoFlag - value ( REQUIRED | MULTIVALUED | NOT_CREATABLE | NOT_UPDATEABLE | NOT_READABLE | NOT_RETURNED_BY_DEFAULT ) #REQUIRED -> -<!ELEMENT ConnectorObject (ObjectClass,Attributes)> -<!ELEMENT Attributes ((%attributeTypes;)*)> - -<!ELEMENT ObjectClass EMPTY> -<!ATTLIST ObjectClass - type CDATA #REQUIRED -> - -<!ELEMENT ObjectClassInfo (AttributeInfos)> -<!ATTLIST ObjectClassInfo - type CDATA #REQUIRED - container CDATA #IMPLIED -> -<!ELEMENT AttributeInfos ((AttributeInfo)*)> - -<!ELEMENT Schema (ObjectClassInfos,OperationOptionInfos,objectClassesByOperation,optionsByOperation)> -<!ELEMENT ObjectClassInfos ((ObjectClassInfo)*)> -<!ELEMENT OperationOptionInfos ((OperationOptionInfo)*)> -<!ELEMENT objectClassesByOperation (Map)> -<!ELEMENT optionsByOperation (Map)> - -<!ELEMENT scriptText (#PCDATA)> -<!ELEMENT scriptArguments (Map)> - -<!ELEMENT Script (scriptText)> -<!ATTLIST Script - scriptLanguage CDATA #REQUIRED -> - -<!ELEMENT ScriptContext (scriptArguments,scriptText)> -<!ATTLIST ScriptContext - scriptLanguage CDATA #REQUIRED -> - -<!ELEMENT OperationOptions (options)> -<!ELEMENT options (Map)> -<!ELEMENT OperationOptionInfo EMPTY> -<!ATTLIST OperationOptionInfo - name CDATA #REQUIRED - type CDATA #REQUIRED -> -<!ELEMENT SyncDeltaType EMPTY> -<!ATTLIST SyncDeltaType - value ( CREATE_OR_UPDATE | DELETE ) #REQUIRED -> - -<!ELEMENT SyncToken (value)> -<!ELEMENT SyncDelta (SyncDeltaType,SyncToken,PreviousUid,Uid,ConnectorObject?)> - -<!ELEMENT PreviousUid (#PCDATA)> - -<!ELEMENT QualifiedUid (ObjectClass,Uid)> - - -<!--=======================================================--> -<!--= =--> -<!--= Filters =--> -<!--= =--> -<!--=======================================================--> - - -<!ELEMENT attribute (%attributeTypes;)> -<!ELEMENT AndFilter ((%filterTypes;),(%filterTypes;))> -<!ELEMENT ContainsFilter (attribute)> -<!ELEMENT EndsWithFilter (attribute)> -<!ELEMENT EqualsFilter (attribute)> -<!ELEMENT GreaterThanFilter (attribute)> -<!ELEMENT GreaterThanOrEqualFilter (attribute)> -<!ELEMENT LessThanFilter (attribute)> -<!ELEMENT LessThanOrEqualFilter (attribute)> -<!ELEMENT NotFilter (%filterTypes;)> -<!ELEMENT OrFilter ((%filterTypes;),(%filterTypes;))> -<!ELEMENT StartsWithFilter (attribute)> -<!ELEMENT ContainsAllValuesFilter (attribute)> - -<!--=======================================================--> -<!--= =--> -<!--= Messages =--> -<!--= =--> -<!--=======================================================--> -<!ELEMENT HelloRequest EMPTY> -<!ELEMENT ConnectorInfos ((ConnectorInfo)*)> -<!ELEMENT exception (%exceptionTypes;)> -<!ELEMENT HelloResponse (exception,ConnectorInfos)> -<!ELEMENT OperationRequest (ConnectorKey,APIConfiguration,Arguments)> -<!ATTLIST OperationRequest - operation CDATA #REQUIRED - operationMethodName CDATA #REQUIRED -> -<!ELEMENT Arguments ((%xmlObject;)*)> -<!ELEMENT OperationResponseEnd EMPTY> -<!ELEMENT OperationResponsePart (exception,result)> -<!ELEMENT result ((%xmlObject;)*)> -<!ELEMENT OperationRequestMoreData EMPTY> -<!ELEMENT OperationRequestStopData EMPTY> -<!ELEMENT OperationResponsePause EMPTY> -<!ELEMENT EchoMessage (value,objectXml?)> -<!ELEMENT objectXml (#PCDATA)> - - - Test Framework Value - - - Account - - - Person - - - Group - - - Organization - - diff --git a/FrameworkInternal/Security.cs b/FrameworkInternal/Security.cs deleted file mode 100644 index 3adf608..0000000 --- a/FrameworkInternal/Security.cs +++ /dev/null @@ -1,138 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 Org.IdentityConnectors.Common.Security; -using System.Text; -using System.Security.Cryptography; - -namespace Org.IdentityConnectors.Common.Security.Impl -{ - public class EncryptorFactoryImpl : EncryptorFactory - { - private readonly Encryptor _defaultEncryptor; - - public EncryptorFactoryImpl() - { - _defaultEncryptor = new EncryptorImpl(); - } - - public override Encryptor GetDefaultEncryptor() - { - return _defaultEncryptor; - } - } - - public class EncryptorImpl : Encryptor - { - private readonly static byte[] _defaultKeyBytes = - { - (byte) 0x23,(byte) 0x65,(byte) 0x87,(byte) 0x22, - (byte) 0x59,(byte) 0x78,(byte) 0x54,(byte) 0x43, - (byte) 0x64,(byte) 0x05,(byte) 0x6A,(byte) 0xBD, - (byte) 0x34,(byte) 0xA2,(byte) 0x34,(byte) 0x57, - }; - private readonly static byte[] _defaultIvBytes = - { - (byte) 0x51,(byte) 0x65,(byte) 0x22,(byte) 0x23, - (byte) 0x64,(byte) 0x05,(byte) 0x6A,(byte) 0xBE, - (byte) 0x51,(byte) 0x65,(byte) 0x22,(byte) 0x23, - (byte) 0x64,(byte) 0x05,(byte) 0x6A,(byte) 0xBE, - }; - - public EncryptorImpl() - { - } - - public UnmanagedArray Decrypt(byte[] bytes) - { - using (SymmetricAlgorithm algo = Aes.Create()) - { - algo.Padding = PaddingMode.PKCS7; - algo.Mode = CipherMode.CBC; - algo.Key = _defaultKeyBytes; - algo.IV = _defaultIvBytes; - using (ICryptoTransform transform = algo.CreateDecryptor()) - { - return Decrypt2(bytes, transform); - } - } - } - - private unsafe UnmanagedArray Decrypt2(byte[] bytes, ICryptoTransform transform) - { - byte[] managedBytes = transform.TransformFinalBlock(bytes, 0, bytes.Length); - //pin it ASAP. this is a small race condition that is unavoidable due - //to the way the crypto API's return byte[]. - fixed (byte* dummy = managedBytes) - { - try - { - UnmanagedByteArray rv = new UnmanagedByteArray(managedBytes.Length); - for (int i = 0; i < rv.Length; i++) - { - rv[i] = managedBytes[i]; - } - return rv; - } - finally - { - SecurityUtil.Clear(managedBytes); - } - } - } - - public byte[] Encrypt(UnmanagedArray bytes) - { - using (SymmetricAlgorithm algo = Aes.Create()) - { - algo.Padding = PaddingMode.PKCS7; - algo.Mode = CipherMode.CBC; - algo.Key = _defaultKeyBytes; - algo.IV = _defaultIvBytes; - using (ICryptoTransform transform = algo.CreateEncryptor()) - { - return Encrypt2(bytes, transform); - } - } - } - - private unsafe byte[] Encrypt2(UnmanagedArray bytes, ICryptoTransform transform) - { - byte[] managedBytes = new byte[bytes.Length]; - fixed (byte* dummy = managedBytes) - { - try - { - SecurityUtil.UnmanagedBytesToManagedBytes(bytes, managedBytes); - byte[] rv = transform.TransformFinalBlock(managedBytes, 0, managedBytes.Length); - return rv; - } - finally - { - SecurityUtil.Clear(managedBytes); - } - } - } - } -} \ No newline at end of file diff --git a/FrameworkInternal/Serializer.cs b/FrameworkInternal/Serializer.cs deleted file mode 100644 index 8030000..0000000 --- a/FrameworkInternal/Serializer.cs +++ /dev/null @@ -1,2875 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.IO; -using System.Collections.Generic; -using System.Security; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Common.Pooling; -using Org.IdentityConnectors.Common.Security; -using Org.IdentityConnectors.Framework.Api; -using Org.IdentityConnectors.Framework.Api.Operations; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Common.Objects.Filters; -using Org.IdentityConnectors.Framework.Common.Exceptions; -using Org.IdentityConnectors.Framework.Common.Serializer; -using Org.IdentityConnectors.Framework.Impl.Api; -using Org.IdentityConnectors.Framework.Impl.Api.Remote; -using Org.IdentityConnectors.Framework.Impl.Api.Remote.Messages; -using Org.IdentityConnectors.Framework.Impl.Serializer.Binary; -using Org.IdentityConnectors.Framework.Impl.Serializer.Xml; -using System.Linq; -using System.Globalization; -namespace Org.IdentityConnectors.Framework.Impl.Serializer -{ - #region Serialization Framework - internal abstract class AbstractObjectSerializationHandler - : ObjectTypeMapperImpl, ObjectSerializationHandler - { - - protected AbstractObjectSerializationHandler(Type handledClass, - String type) - : base(handledClass, type) - { - } - /// - /// Called to serialize the object. - /// - abstract public void Serialize(Object obj, ObjectEncoder encoder); - - /// - /// Called to deserialize the object. - /// - abstract public Object Deserialize(ObjectDecoder decoder); - } - - - internal class EnumSerializationHandler : - AbstractObjectSerializationHandler - { - public EnumSerializationHandler(Type clazz, String name) - : base(clazz, name) - { - } - - public override object Deserialize(ObjectDecoder decoder) - { - String val = decoder.ReadStringField("value", null); - Type enumClass = HandledObjectType; - Object rv = Enum.Parse(enumClass, val); - return rv; - } - - public override void Serialize(object obj, ObjectEncoder encoder) - { - Enum e = (Enum)obj; - encoder.WriteStringField("value", Enum.GetName(e.GetType(), e)); - } - } - - /// - /// Interface to abstract away the difference between deserializing - /// xml and binary - /// - internal interface ObjectDecoder - { - /// - /// Reads an object using the appropriate serializer for that object - /// - /// A hint of the field name. Ignored for binary - /// serialization. The subelement name for xml serialization - Object ReadObjectField(String fieldName, - Type expectedType, - Object dflt); - - /// - /// Reads a bool. - /// - /// A hint of the field name. Ignored for binary - /// serialization. The subelement name for xml serialization - bool ReadBooleanField(String fieldName, bool dflt); - - /// - /// Reads an int. - /// - /// A hint of the field name. Ignored for binary - /// serialization. The subelement name for xml serialization - int ReadIntField(String fieldName, int dflt); - - /// - /// Reads a long. - /// - /// A hint of the field name. Ignored for binary - /// serialization. The subelement name for xml serialization - long ReadLongField(String fieldName, long dflt); - - /// - /// Reads a float. - /// - /// A hint of the field name. Ignored for binary - /// serialization. The subelement name for xml serialization - float ReadFloatField(String fieldName, float dflt); - - /// - /// Reads a double. - /// - /// A hint of the field name. Ignored for binary - /// serialization. The subelement name for xml serialization - /// The value to serialize - double ReadDoubleField(String fieldName, double dflt); - - /// - /// Reads a double. - /// - /// A hint of the field name. Ignored for binary - /// serialization. The subelement name for xml serialization - /// The value to serialize - string ReadStringField(String fieldName, string dflt); - - /// - /// Reads a double. - /// - /// A hint of the field name. Ignored for binary - /// serialization. The subelement name for xml serialization - /// The value to serialize - Type ReadClassField(String fieldName, Type dflt); - - /// - /// Reads the value in-line. - /// - String ReadStringContents(); - - /// - /// Reads the value in-line. - /// - bool ReadBooleanContents(); - - /// - /// Reads the value in-line. - /// - int ReadIntContents(); - - /// - /// reads the value in-line. - /// - long ReadLongContents(); - - /// - /// Reads the value in-line. - /// - float ReadFloatContents(); - - /// - /// reads the value in-line. - /// - double ReadDoubleContents(); - - /// - /// reads the value in-line. - /// - byte[] ReadByteArrayContents(); - - /// - /// reads the value in-line. - /// - Type ReadClassContents(); - - /// - /// Returns the number of anonymous sub-objects. - /// - int GetNumSubObjects(); - - /// - /// Reads a sub-object - /// - Object ReadObjectContents(int index); - } - - /// - /// Interface to abstract away the difference between serializing - /// xml and binary - /// - internal interface ObjectEncoder - { - /// - /// Writes an object using the appropriate serializer for that object - /// - /// A hint of the field name. Ignored for binary - /// serialization. Becomes the subelement name for xml serialization - /// The object to serialize - void WriteObjectField(String fieldName, Object obj, bool inline); - - /// - /// Writes a boolean. - /// - /// A hint of the field name. Ignored for binary - /// serialization. Becomes the subelement name for xml serialization - /// The value to serialize - void WriteBooleanField(String fieldName, bool v); - - /// - /// Writes an int. - /// - /// A hint of the field name. Ignored for binary - /// serialization. Becomes the subelement name for xml serialization - /// The value to serialize - void WriteIntField(String fieldName, int v); - - /// - /// Writes a long. - /// - /// A hint of the field name. Ignored for binary - /// serialization. Becomes the subelement name for xml serialization - /// The value to serialize - void WriteLongField(String fieldName, long v); - - /// - /// Writes a float. - /// - /// A hint of the field name. Ignored for binary - /// serialization. Becomes the subelement name for xml serialization - /// The value to serialize - void WriteFloatField(String fieldName, float v); - - /// - /// Writes a double. - /// - /// A hint of the field name. Ignored for binary - /// serialization. Becomes the subelement name for xml serialization - /// The value to serialize - void WriteDoubleField(String fieldName, double v); - - /// - /// Writes a double. - /// - /// A hint of the field name. Ignored for binary - /// serialization. Becomes the subelement name for xml serialization - /// The value to serialize - void WriteStringField(String fieldName, string v); - - /// - /// Writes a double. - /// - /// A hint of the field name. Ignored for binary - /// serialization. Becomes the subelement name for xml serialization - /// The value to serialize - void WriteClassField(String fieldName, Type v); - - /// - /// Writes the value in-line. - /// - void WriteStringContents(String str); - - /// - /// Writes the value in-line. - /// - void WriteBooleanContents(bool v); - - /// - /// Writes the value in-line. - /// - void WriteIntContents(int v); - - /// - /// Writes the value in-line. - /// - void WriteLongContents(long v); - - /// - /// Writes the value in-line. - /// - void WriteFloatContents(float v); - - /// - /// Writes the value in-line. - /// - void WriteDoubleContents(double v); - - /// - /// Special case for byte [] that uses base64 encoding for XML - /// - void WriteByteArrayContents(byte[] v); - - /// - /// Writes the value in-line. - /// - void WriteClassContents(Type v); - - /// - /// Writes a sub-object - /// - void WriteObjectContents(object o); - } - - /// - /// Interface to be implemented to handle the serialization/ - /// deserialization of an object. - /// - internal interface ObjectSerializationHandler : ObjectTypeMapper - { - /// - /// Called to serialize the object. - /// - void Serialize(Object obj, ObjectEncoder encoder); - - /// - /// Called to deserialize the object. - /// - Object Deserialize(ObjectDecoder decoder); - } - - internal static class ObjectSerializerRegistry - { - private static readonly IList HANDLERS = - new List(); - - private static readonly IDictionary - HANDLERS_BY_SERIAL_TYPE = new Dictionary(); - - static ObjectSerializerRegistry() - { - CollectionUtil.AddAll(HANDLERS, Primitives.HANDLERS); - CollectionUtil.AddAll(HANDLERS, OperationMappings.MAPPINGS); - CollectionUtil.AddAll(HANDLERS, APIConfigurationHandlers.HANDLERS); - CollectionUtil.AddAll(HANDLERS, FilterHandlers.HANDLERS); - CollectionUtil.AddAll(HANDLERS, CommonObjectHandlers.HANDLERS); - CollectionUtil.AddAll(HANDLERS, MessageHandlers.HANDLERS); - //object is special - just map the type, but don't actually - //serialize - HANDLERS.Add(new ObjectTypeMapperImpl(typeof(object), "Object")); - - foreach (ObjectTypeMapper handler in HANDLERS) - { - if (HANDLERS_BY_SERIAL_TYPE.ContainsKey(handler.HandledSerialType)) - { - throw new Exception("More than one handler of the" + - " same type: " + handler.HandledSerialType); - } - HANDLERS_BY_SERIAL_TYPE[handler.HandledSerialType] = - handler; - } - } - - /// - /// Mapping by class. - /// - /// - /// Dynamically built since actual class may be - /// a subclass. - /// - private static readonly IDictionary - HANDLERS_BY_OBJECT_TYPE = - new Dictionary(); - - public static ObjectTypeMapper GetMapperBySerialType(String type) - { - return CollectionUtil.GetValue(HANDLERS_BY_SERIAL_TYPE, type, null); - } - - public static ObjectTypeMapper GetMapperByObjectType(Type clazz) - { - lock (HANDLERS_BY_OBJECT_TYPE) - { - ObjectTypeMapper rv = - CollectionUtil.GetValue(HANDLERS_BY_OBJECT_TYPE, clazz, null); - if (rv == null) - { - foreach (ObjectTypeMapper handler in HANDLERS) - { - IDelegatingObjectTypeMapper delegator = - handler as IDelegatingObjectTypeMapper; - ObjectTypeMapper effectiveHandler; - if (delegator != null) - { - effectiveHandler = delegator.FindMapperDelegate(clazz); - } - else - { - effectiveHandler = handler; - } - if (effectiveHandler != null) - { - Type handledClass = - effectiveHandler.HandledObjectType; - if (effectiveHandler.MatchSubclasses) - { - if (handledClass.IsAssignableFrom(clazz)) - { - rv = effectiveHandler; - break; - } - } - else if (handledClass.Equals(clazz)) - { - rv = effectiveHandler; - break; - } - } - } - HANDLERS_BY_OBJECT_TYPE[clazz] = rv; - } - return rv; - } - } - public static ObjectSerializationHandler GetHandlerBySerialType(String type) - { - ObjectTypeMapper rv = GetMapperBySerialType(type); - return rv as ObjectSerializationHandler; - } - - public static ObjectSerializationHandler GetHandlerByObjectType(Type clazz) - { - ObjectTypeMapper rv = GetMapperByObjectType(clazz); - return rv as ObjectSerializationHandler; - } - } - - /// - /// ObjectTypeMappers can implement this interface as well. If - /// they do, they can handle specific generic types as well. - /// - internal interface IDelegatingObjectTypeMapper - { - ObjectTypeMapper FindMapperDelegate(Type type); - } - - /// - /// Interface to be implemented to handle the serialization/ - /// deserialization of an object. - /// - internal interface ObjectTypeMapper - { - /// - /// Returns the type of object being serialized. - /// - /// - /// This is - /// an abstract type name that is intended to be language - /// neutral. - /// - String HandledSerialType { get; } - - /// - /// Returns the java class handled by this handler. - /// - Type HandledObjectType { get; } - - /// - /// Should we match subclasses of the given class or only - /// the exact class? - /// - bool MatchSubclasses { get; } - } - - internal class ObjectTypeMapperImpl : ObjectTypeMapper - { - private Type _handledClass; - private String _handledType; - - public ObjectTypeMapperImpl(Type handledClass, String handledType) - { - _handledClass = handledClass; - _handledType = handledType; - } - - public Type HandledObjectType - { - get - { - return _handledClass; - } - } - - public String HandledSerialType - { - get - { - return _handledType; - } - } - - public virtual bool MatchSubclasses - { - get - { - return false; - } - } - } - - internal abstract class AbstractExceptionHandler : AbstractObjectSerializationHandler - where T : Exception - { - protected AbstractExceptionHandler(String typeName) - : base(typeof(T), typeName) - { - } - - public override Object Deserialize(ObjectDecoder decoder) - { - String message = decoder.ReadStringField("message", null); - return CreateException(message); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - Exception val = (Exception)obj; - encoder.WriteStringField("message", val.Message); - } - public override bool MatchSubclasses - { - get { return true; } - } - protected abstract T CreateException(String message); - } - - - #endregion - - #region Primitives - - internal static class Primitives - { - public static readonly IList HANDLERS = - new List(); - static Primitives() - { - HANDLERS.Add(new BooleanHandler(typeof(bool?), "Boolean")); - HANDLERS.Add(new BooleanHandler(typeof(bool), "boolean")); - HANDLERS.Add(new CharacterHandler(typeof(char?), "Character")); - HANDLERS.Add(new CharacterHandler(typeof(char), "char")); - HANDLERS.Add(new IntegerHandler(typeof(int?), "Integer")); - HANDLERS.Add(new IntegerHandler(typeof(int), "int")); - HANDLERS.Add(new LongHandler(typeof(long?), "Long")); - HANDLERS.Add(new LongHandler(typeof(long), "long")); - HANDLERS.Add(new FloatHandler(typeof(float?), "Float")); - HANDLERS.Add(new FloatHandler(typeof(float), "float")); - HANDLERS.Add(new DoubleHandler(typeof(double?), "Double")); - HANDLERS.Add(new DoubleHandler(typeof(double), "double")); - HANDLERS.Add(new StringHandler()); - HANDLERS.Add(new URIHandler()); - HANDLERS.Add(new FileHandler()); - HANDLERS.Add(new BigIntegerHandler()); - HANDLERS.Add(new BigDecimalHandler()); - HANDLERS.Add(new ByteArrayHandler()); - HANDLERS.Add(new ClassHandler()); - HANDLERS.Add(new MapEntryHandler()); - HANDLERS.Add(new MapHandler()); - HANDLERS.Add(new ListHandler()); - HANDLERS.Add(new SetHandler()); - HANDLERS.Add(new LocaleHandler()); - HANDLERS.Add(new GuardedByteArrayHandler()); - HANDLERS.Add(new GuardedStringHandler()); - } - private class BooleanHandler : AbstractObjectSerializationHandler - { - public BooleanHandler(Type objectType, String serialType) - : base(objectType, serialType) - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - bool val = decoder.ReadBooleanContents(); - return val; - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - bool val = (bool)obj; - encoder.WriteBooleanContents(val); - } - } - private class CharacterHandler : AbstractObjectSerializationHandler - { - public CharacterHandler(Type objectType, String serialType) - : base(objectType, serialType) - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - String val = decoder.ReadStringContents(); - return val.ToCharArray()[0]; - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - char val = (char)obj; - encoder.WriteStringContents(val.ToString()); - } - } - private class IntegerHandler : AbstractObjectSerializationHandler - { - public IntegerHandler(Type objectType, String serialType) - : base(objectType, serialType) - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - int val = decoder.ReadIntContents(); - return val; - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - int val = (int)obj; - encoder.WriteIntContents(val); - } - } - private class LongHandler : AbstractObjectSerializationHandler - { - public LongHandler(Type objectType, String serialType) - : base(objectType, serialType) - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - long val = decoder.ReadLongContents(); - return val; - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - long val = (long)obj; - encoder.WriteLongContents(val); - } - } - private class FloatHandler : AbstractObjectSerializationHandler - { - public FloatHandler(Type objectType, String serialType) - : base(objectType, serialType) - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - float val = decoder.ReadFloatContents(); - return val; - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - float val = (float)obj; - encoder.WriteFloatContents(val); - } - } - private class DoubleHandler : AbstractObjectSerializationHandler - { - public DoubleHandler(Type objectType, String serialType) - : base(objectType, serialType) - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - double val = decoder.ReadDoubleContents(); - return val; - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - double val = (double)obj; - encoder.WriteDoubleContents(val); - } - } - private class StringHandler : AbstractObjectSerializationHandler - { - public StringHandler() - : base(typeof(string), "String") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - string val = decoder.ReadStringContents(); - return val; - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - string val = (string)obj; - encoder.WriteStringContents(val); - } - } - private class URIHandler : AbstractObjectSerializationHandler - { - public URIHandler() - : base(typeof(Uri), "URI") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - string val = decoder.ReadStringContents(); - return new Uri(val); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - Uri val = (Uri)obj; - encoder.WriteStringContents(val.ToString()); - } - } - private class FileHandler : AbstractObjectSerializationHandler - { - public FileHandler() - : base(typeof(FileName), "File") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - string val = decoder.ReadStringContents(); - return new FileName(val); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - FileName val = (FileName)obj; - encoder.WriteStringContents(val.Path); - } - } - private class BigDecimalHandler : AbstractObjectSerializationHandler - { - public BigDecimalHandler() - : base(typeof(BigDecimal), "BigDecimal") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - BigInteger unscaled = - new BigInteger(decoder.ReadStringField("unscaled", null)); - int scale = decoder.ReadIntField("scale", 0); - return new BigDecimal(unscaled, scale); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - BigDecimal val = (BigDecimal)obj; - encoder.WriteStringField("unscaled", val.UnscaledValue.Value); - encoder.WriteIntField("scale", val.Scale); - } - } - private class BigIntegerHandler : AbstractObjectSerializationHandler - { - public BigIntegerHandler() - : base(typeof(BigInteger), "BigInteger") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - string val = decoder.ReadStringContents(); - return new BigInteger(val); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - BigInteger val = (BigInteger)obj; - encoder.WriteStringContents(val.Value); - } - } - private class ByteArrayHandler : AbstractObjectSerializationHandler - { - public ByteArrayHandler() - : base(typeof(byte[]), "ByteArray") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - return decoder.ReadByteArrayContents(); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - byte[] val = (byte[])obj; - encoder.WriteByteArrayContents(val); - } - } - private class ClassHandler : AbstractObjectSerializationHandler - { - public ClassHandler() - : base(typeof(Type), "Class") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - return decoder.ReadClassContents(); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - Type val = (Type)obj; - encoder.WriteClassContents(val); - } - - /// - /// In C#, the actual Type of Type is RuntimeType - /// - public override bool MatchSubclasses - { - get { return true; } - } - } - - private class MapEntry - { - internal object key; - internal object val; - public MapEntry(object key, object val) - { - this.key = key; - this.val = val; - } - } - private class MapEntryHandler : - AbstractObjectSerializationHandler - { - - public MapEntryHandler() - : base(typeof(MapEntry), "MapEntry") - { - } - public override Object Deserialize(ObjectDecoder decoder) - { - Object key = decoder.ReadObjectContents(0); - Object val = decoder.ReadObjectContents(1); - return new MapEntry(key, val); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - MapEntry entry = (MapEntry)obj; - encoder.WriteObjectContents(entry.key); - encoder.WriteObjectContents(entry.val); - } - } - private class MapHandler : - AbstractObjectSerializationHandler, - IDelegatingObjectTypeMapper - { - public MapHandler() - : base(typeof(IDictionary), "Map") - { - } - public ObjectTypeMapper FindMapperDelegate(Type type) - { - //get the IDictionary interface that this type implements - Type interfaceType = ReflectionUtil.FindInHierarchyOf - (typeof(IDictionary<,>), type); - if (interfaceType != null) - { - Type[] keyAndValue = interfaceType.GetGenericArguments(); - if (keyAndValue.Length != 2) - { - throw new Exception("Cannot serialize type: " + type); - } - Type mapHandlerRawType = typeof(MapHandler<,>); - Type mapHandlerType = - mapHandlerRawType.MakeGenericType(keyAndValue); - return (ObjectTypeMapper)Activator.CreateInstance(mapHandlerType); - } - return null; - } - public override Object Deserialize(ObjectDecoder decoder) - { - bool caseInsensitive = - decoder.ReadBooleanField("caseInsensitive", false); - if (caseInsensitive) - { - IDictionary rv = - CollectionUtil.NewCaseInsensitiveDictionary(); - int count = decoder.GetNumSubObjects(); - for (int i = 0; i < count; i++) - { - MapEntry entry = (MapEntry)decoder.ReadObjectContents(i); - rv["" + entry.key] = entry.val; - } - return rv; - } - else - { - IDictionary rv = - new Dictionary(); - int count = decoder.GetNumSubObjects(); - for (int i = 0; i < count; i++) - { - MapEntry entry = (MapEntry)decoder.ReadObjectContents(i); - rv[entry.key] = entry.val; - } - return rv; - } - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - IDictionary map = (IDictionary)obj; - if (CollectionUtil.IsCaseInsensitiveDictionary(map)) - { - encoder.WriteBooleanField("caseInsensitive", true); - } - else if (map is SortedDictionary) - { - throw new Exception("Serialization of SortedDictionary not supported"); - } - foreach (KeyValuePair entry in map) - { - MapEntry myEntry = new MapEntry(entry.Key, entry.Value); - encoder.WriteObjectContents(myEntry); - } - } - - public override bool MatchSubclasses - { - get { return true; } - } - } - private class ListHandler : - AbstractObjectSerializationHandler, - IDelegatingObjectTypeMapper - { - - public ListHandler() - : base(typeof(IList), "List") - { - } - public ObjectTypeMapper FindMapperDelegate(Type type) - { - //in C#, arrays implement IList - if (type.IsArray) - { - return null; - } - //get the IList interface that this type implements - Type interfaceType = ReflectionUtil.FindInHierarchyOf - (typeof(IList<>), type); - if (interfaceType != null) - { - Type[] val = interfaceType.GetGenericArguments(); - if (val.Length != 1) - { - throw new Exception("Cannot serialize type: " + type); - } - Type listHandlerRawType = typeof(ListHandler<>); - Type listHandlerType = - listHandlerRawType.MakeGenericType(val); - return (ObjectTypeMapper)Activator.CreateInstance(listHandlerType); - } - return null; - } - public override Object Deserialize(ObjectDecoder decoder) - { - IList rv = - new List(); - int count = decoder.GetNumSubObjects(); - for (int i = 0; i < count; i++) - { - rv.Add(decoder.ReadObjectContents(i)); - } - return rv; - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - IList list = (IList)obj; - foreach (T o in list) - { - encoder.WriteObjectContents(o); - } - } - - public override bool MatchSubclasses - { - get { return true; } - } - } - private class SetHandler : - AbstractObjectSerializationHandler, - IDelegatingObjectTypeMapper - { - - public SetHandler() - : base(typeof(ICollection), "Set") - { - } - public ObjectTypeMapper FindMapperDelegate(Type type) - { - //in C#, arrays implement IList - if (type.IsArray) - { - return null; - } - - //get the IList interface that this type implements - Type interfaceType = ReflectionUtil.FindInHierarchyOf - (typeof(ICollection<>), type); - if (interfaceType != null) - { - Type[] val = interfaceType.GetGenericArguments(); - if (val.Length != 1) - { - throw new Exception("Cannot serialize type: " + type); - } - Type setHandlerRawType = typeof(SetHandler<>); - Type setHandlerType = - setHandlerRawType.MakeGenericType(val); - return (ObjectTypeMapper)Activator.CreateInstance(setHandlerType); - } - return null; - } - public override Object Deserialize(ObjectDecoder decoder) - { - bool caseInsensitive = - decoder.ReadBooleanField("caseInsensitive", false); - if (caseInsensitive) - { - ICollection rv = - CollectionUtil.NewCaseInsensitiveSet(); - int count = decoder.GetNumSubObjects(); - for (int i = 0; i < count; i++) - { - rv.Add("" + decoder.ReadObjectContents(i)); - } - return rv; - } - else - { - ICollection rv = - new HashSet(); - int count = decoder.GetNumSubObjects(); - for (int i = 0; i < count; i++) - { - rv.Add(decoder.ReadObjectContents(i)); - } - return rv; - } - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - ICollection list = (ICollection)obj; - if (CollectionUtil.IsCaseInsensitiveSet(list)) - { - encoder.WriteBooleanField("caseInsensitive", true); - } - foreach (T o in list) - { - encoder.WriteObjectContents(o); - } - } - - public override bool MatchSubclasses - { - get { return true; } - } - } - private class LocaleHandler : AbstractObjectSerializationHandler - { - public LocaleHandler() - : base(typeof(CultureInfo), "Locale") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - string language = decoder.ReadStringField("language", ""); - string country = decoder.ReadStringField("country", ""); - string variant = decoder.ReadStringField("variant", ""); - Locale locale = new Locale(language, country, variant); - return locale.ToCultureInfo(); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - CultureInfo cultureInfo = (CultureInfo)obj; - Locale locale = Locale.FindLocale(cultureInfo); - encoder.WriteStringField("language", locale.Language); - encoder.WriteStringField("country", locale.Country); - encoder.WriteStringField("variant", locale.Variant); - - } - } - - private class GuardedByteArrayHandler : AbstractObjectSerializationHandler - { - public GuardedByteArrayHandler() - : base(typeof(GuardedByteArray), "GuardedByteArray") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - byte[] encryptedBytes = null; - UnmanagedArray clearBytes = null; - try - { - encryptedBytes = decoder.ReadByteArrayContents(); - clearBytes = EncryptorFactory.GetInstance().GetDefaultEncryptor().Decrypt(encryptedBytes); - GuardedByteArray rv = new GuardedByteArray(); - for (int i = 0; i < clearBytes.Length; i++) - { - rv.AppendByte(clearBytes[i]); - } - return rv; - } - finally - { - if (clearBytes != null) - { - clearBytes.Dispose(); - } - SecurityUtil.Clear(encryptedBytes); - } - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - GuardedByteArray str = (GuardedByteArray)obj; - str.Access( - clearBytes => - { - byte[] encryptedBytes = null; - try - { - encryptedBytes = EncryptorFactory.GetInstance().GetDefaultEncryptor().Encrypt(clearBytes); - encoder.WriteByteArrayContents(encryptedBytes); - } - finally - { - SecurityUtil.Clear(encryptedBytes); - } - }); - } - } - - private class GuardedStringHandler : AbstractObjectSerializationHandler - { - public GuardedStringHandler() - : base(typeof(GuardedString), "GuardedString") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - byte[] encryptedBytes = null; - UnmanagedArray clearBytes = null; - UnmanagedArray clearChars = null; - try - { - encryptedBytes = decoder.ReadByteArrayContents(); - clearBytes = EncryptorFactory.GetInstance().GetDefaultEncryptor().Decrypt(encryptedBytes); - clearChars = SecurityUtil.BytesToChars(clearBytes); - GuardedString rv = new GuardedString(); - for (int i = 0; i < clearChars.Length; i++) - { - rv.AppendChar(clearChars[i]); - } - return rv; - } - finally - { - if (clearBytes != null) - { - clearBytes.Dispose(); - } - if (clearChars != null) - { - clearChars.Dispose(); - } - SecurityUtil.Clear(encryptedBytes); - } - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - GuardedString str = (GuardedString)obj; - str.Access( - clearChars => - { - UnmanagedArray clearBytes = null; - byte[] encryptedBytes = null; - try - { - clearBytes = SecurityUtil.CharsToBytes(clearChars); - encryptedBytes = EncryptorFactory.GetInstance().GetDefaultEncryptor().Encrypt(clearBytes); - encoder.WriteByteArrayContents(encryptedBytes); - } - finally - { - if (clearBytes != null) - { - clearBytes.Dispose(); - } - SecurityUtil.Clear(encryptedBytes); - } - }); - } - } - } - #endregion - - #region APIConfigurationHandlers - internal static class APIConfigurationHandlers - { - public static readonly IList HANDLERS = - new List(); - static APIConfigurationHandlers() - { - HANDLERS.Add(new ConnectionPoolingConfigurationHandler()); - HANDLERS.Add(new ConfigurationPropertyHandler()); - HANDLERS.Add(new ConfigurationPropertiesHandler()); - HANDLERS.Add(new APIConfigurationHandler()); - HANDLERS.Add(new ConnectorMessagesHandler()); - HANDLERS.Add(new ConnectorKeyHandler()); - HANDLERS.Add(new ConnectorInfoHandler()); - } - private class ConnectionPoolingConfigurationHandler : AbstractObjectSerializationHandler - { - public ConnectionPoolingConfigurationHandler() - : base(typeof(ObjectPoolConfiguration), "ObjectPoolConfiguration") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - ObjectPoolConfiguration rv = - new ObjectPoolConfiguration(); - rv.MaxObjects = (decoder.ReadIntField("maxObjects", rv.MaxObjects)); - rv.MaxIdle = (decoder.ReadIntField("maxIdle", rv.MaxIdle)); - rv.MaxWait = (decoder.ReadLongField("maxWait", rv.MaxWait)); - rv.MinEvictableIdleTimeMillis = ( - decoder.ReadLongField("minEvictableIdleTimeMillis", rv.MinEvictableIdleTimeMillis)); - rv.MinIdle = ( - decoder.ReadIntField("minIdle", rv.MinIdle)); - return rv; - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - ObjectPoolConfiguration val = - (ObjectPoolConfiguration)obj; - encoder.WriteIntField("maxObjects", - val.MaxObjects); - encoder.WriteIntField("maxIdle", - val.MaxIdle); - encoder.WriteLongField("maxWait", - val.MaxWait); - encoder.WriteLongField("minEvictableIdleTimeMillis", - val.MinEvictableIdleTimeMillis); - encoder.WriteIntField("minIdle", - val.MinIdle); - } - } - private class ConfigurationPropertyHandler : AbstractObjectSerializationHandler - { - public ConfigurationPropertyHandler() - : base(typeof(ConfigurationPropertyImpl), "ConfigurationProperty") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - ConfigurationPropertyImpl rv = new ConfigurationPropertyImpl(); - rv.Order = (decoder.ReadIntField("order", 0)); - rv.IsConfidential = (decoder.ReadBooleanField("confidential", false)); - rv.IsRequired = decoder.ReadBooleanField("required", false); - rv.Name = (decoder.ReadStringField("name", null)); - rv.HelpMessageKey = ( - decoder.ReadStringField("helpMessageKey", null)); - rv.DisplayMessageKey = ( - decoder.ReadStringField("displayMessageKey", null)); - rv.ValueType = ( - decoder.ReadClassField("type", null)); - rv.Value = ( - decoder.ReadObjectField("value", null, null)); - ICollection operationsObj = - (ICollection)decoder.ReadObjectField("operations", typeof(ICollection), null); - ICollection> operations = - new HashSet>(); - foreach (object o in operationsObj) - { - Type type = (Type)o; - operations.Add(SafeType.ForRawType(type)); - } - rv.Operations = operations; - - return rv; - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - ConfigurationPropertyImpl val = - (ConfigurationPropertyImpl)obj; - encoder.WriteIntField("order", - val.Order); - encoder.WriteBooleanField("confidential", - val.IsConfidential); - encoder.WriteBooleanField("required", - val.IsRequired); - encoder.WriteStringField("name", - val.Name); - encoder.WriteStringField("helpMessageKey", - val.HelpMessageKey); - encoder.WriteStringField("displayMessageKey", - val.DisplayMessageKey); - encoder.WriteClassField("type", - val.ValueType); - encoder.WriteObjectField("value", - val.Value, - false); - ICollection operationsObj = - new HashSet(); - foreach (SafeType op in val.Operations) - { - operationsObj.Add(op.RawType); - } - encoder.WriteObjectField("operations", operationsObj, true); - } - } - private class ConfigurationPropertiesHandler : AbstractObjectSerializationHandler - { - public ConfigurationPropertiesHandler() - : base(typeof(ConfigurationPropertiesImpl), "ConfigurationProperties") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - ConfigurationPropertiesImpl rv = - new ConfigurationPropertiesImpl(); - IList props = - new List - (); - int count = decoder.GetNumSubObjects(); - for (int i = 0; i < count; i++) - { - ConfigurationPropertyImpl prop = - (ConfigurationPropertyImpl)decoder.ReadObjectContents(i); - props.Add(prop); - } - rv.Properties = props; - return rv; - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - ConfigurationPropertiesImpl val = - (ConfigurationPropertiesImpl)obj; - IList props = - val.Properties; - foreach (ConfigurationPropertyImpl prop in props) - { - encoder.WriteObjectContents(prop); - } - } - } - private class APIConfigurationHandler : AbstractObjectSerializationHandler - { - public APIConfigurationHandler() - : base(typeof(APIConfigurationImpl), "APIConfiguration") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - APIConfigurationImpl rv = new APIConfigurationImpl(); - rv.IsConnectorPoolingSupported = ( - decoder.ReadBooleanField("connectorPoolingSupported", false)); - rv.ConnectorPoolConfiguration = ( - (ObjectPoolConfiguration) - decoder.ReadObjectField("connectorPoolConfiguration", null, null)); - rv.ConfigurationProperties = ((ConfigurationPropertiesImpl) - decoder.ReadObjectField("ConfigurationProperties", typeof(ConfigurationPropertiesImpl), null)); - IDictionary timeoutMapObj = - (IDictionary)decoder.ReadObjectField("timeoutMap", null, null); - IDictionary, int> timeoutMap = - new Dictionary, int>(); - foreach (KeyValuePair entry in timeoutMapObj) - { - Type type = (Type)entry.Key; - int val = (int)entry.Value; - timeoutMap[SafeType.ForRawType(type)] = val; - } - rv.TimeoutMap = timeoutMap; - ICollection supportedOperationsObj = - (ICollection)decoder.ReadObjectField("SupportedOperations", typeof(ICollection), null); - ICollection> supportedOperations = - new HashSet>(); - foreach (object obj in supportedOperationsObj) - { - Type type = (Type)obj; - supportedOperations.Add(SafeType.ForRawType(type)); - } - rv.SupportedOperations = supportedOperations; - rv.ProducerBufferSize = (decoder.ReadIntField("producerBufferSize", 0)); - return rv; - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - APIConfigurationImpl val = - (APIConfigurationImpl)obj; - - ICollection supportedOperations = - new HashSet(); - if (val.SupportedOperations != null) - { - foreach (SafeType op in val.SupportedOperations) - { - supportedOperations.Add(op.RawType); - } - } - IDictionary timeoutMap = - new Dictionary(); - if (val.TimeoutMap != null) - { - foreach (KeyValuePair, int> entry in val.TimeoutMap) - { - timeoutMap[entry.Key.RawType] = entry.Value; - } - } - - encoder.WriteIntField("producerBufferSize", - val.ProducerBufferSize); - encoder.WriteBooleanField("connectorPoolingSupported", - val.IsConnectorPoolingSupported); - encoder.WriteObjectField("connectorPoolConfiguration", - val.ConnectorPoolConfiguration, false); - encoder.WriteObjectField("ConfigurationProperties", - val.ConfigurationProperties, true); - encoder.WriteObjectField("timeoutMap", - timeoutMap, false); - encoder.WriteObjectField("SupportedOperations", - supportedOperations, true); - } - } - private class ConnectorMessagesHandler : AbstractObjectSerializationHandler - { - public ConnectorMessagesHandler() - : base(typeof(ConnectorMessagesImpl), "ConnectorMessages") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - ConnectorMessagesImpl rv = new ConnectorMessagesImpl(); - IDictionary catalogsObj = - (IDictionary)decoder.ReadObjectField("catalogs", null, null); - IDictionary> - catalogs = new Dictionary>(); - foreach (KeyValuePair entry in catalogsObj) - { - CultureInfo key = (CultureInfo)entry.Key; - IDictionary valObj = (IDictionary)entry.Value; - IDictionary val = - CollectionUtil.NewDictionary(valObj); - catalogs[key] = val; - } - rv.Catalogs = (catalogs); - return rv; - - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - ConnectorMessagesImpl val = - (ConnectorMessagesImpl)obj; - encoder.WriteObjectField("catalogs", - val.Catalogs, false); - } - } - - private class ConnectorKeyHandler : AbstractObjectSerializationHandler - { - public ConnectorKeyHandler() - : base(typeof(ConnectorKey), "ConnectorKey") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - String bundleName = - decoder.ReadStringField("bundleName", null); - String bundleVersion = - decoder.ReadStringField("bundleVersion", null); - String connectorName = - decoder.ReadStringField("connectorName", null); - return new ConnectorKey(bundleName, bundleVersion, connectorName); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - ConnectorKey val = (ConnectorKey)obj; - encoder.WriteStringField("bundleName", - val.BundleName); - encoder.WriteStringField("bundleVersion", - val.BundleVersion); - encoder.WriteStringField("connectorName", - val.ConnectorName); - } - } - - private class ConnectorInfoHandler : AbstractObjectSerializationHandler - { - public ConnectorInfoHandler() - : base(typeof(RemoteConnectorInfoImpl), "ConnectorInfo") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - RemoteConnectorInfoImpl rv = new RemoteConnectorInfoImpl(); - rv.ConnectorDisplayNameKey = ( - decoder.ReadStringField("connectorDisplayNameKey", null)); - rv.ConnectorKey = ((ConnectorKey) - decoder.ReadObjectField("ConnectorKey", typeof(ConnectorKey), null)); - rv.Messages = ((ConnectorMessagesImpl) - decoder.ReadObjectField("ConnectorMessages", typeof(ConnectorMessagesImpl), null)); - rv.DefaultAPIConfiguration = ((APIConfigurationImpl) - decoder.ReadObjectField("APIConfiguration", typeof(APIConfigurationImpl), null)); - return rv; - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - RemoteConnectorInfoImpl val = - (RemoteConnectorInfoImpl)obj; - encoder.WriteStringField("connectorDisplayNameKey", - val.ConnectorDisplayNameKey); - encoder.WriteObjectField("ConnectorKey", - val.ConnectorKey, true); - encoder.WriteObjectField("ConnectorMessages", - val.Messages, true); - encoder.WriteObjectField("APIConfiguration", - val.DefaultAPIConfiguration, true); - } - } - - } - #endregion - - #region ObjectSerializerFactoryImpl - public class ObjectSerializerFactoryImpl : ObjectSerializerFactory - { - public override BinaryObjectDeserializer NewBinaryDeserializer(Stream i) - { - return new BinaryObjectDecoder(i); - } - - public override BinaryObjectSerializer NewBinarySerializer(Stream os) - { - return new BinaryObjectEncoder(os); - } - public override XmlObjectSerializer NewXmlSerializer(TextWriter w, - bool includeHeader, - bool multiObject) - { - return new XmlObjectSerializerImpl(w, includeHeader, multiObject); - } - - public override void DeserializeXmlStream(TextReader reader, - XmlObjectResultsHandler handler, - bool validate) - { - XmlObjectParser.parse(reader, handler, validate); - } - - } - #endregion - - #region OperationMappings - internal static class OperationMappings - { - public static readonly IList MAPPINGS = - new List(); - - static OperationMappings() - { - MAPPINGS.Add(new ObjectTypeMapperImpl(typeof(AuthenticationApiOp), - "AuthenticationApiOp")); - MAPPINGS.Add(new ObjectTypeMapperImpl(typeof(ResolveUsernameApiOp), - "ResolveUsernameApiOp")); - MAPPINGS.Add(new ObjectTypeMapperImpl(typeof(SearchApiOp), - "SearchApiOp")); - MAPPINGS.Add(new ObjectTypeMapperImpl(typeof(ValidateApiOp), - "ValidateApiOp")); - MAPPINGS.Add(new ObjectTypeMapperImpl(typeof(CreateApiOp), - "CreateApiOp")); - MAPPINGS.Add(new ObjectTypeMapperImpl(typeof(SchemaApiOp), - "SchemaApiOp")); - MAPPINGS.Add(new ObjectTypeMapperImpl(typeof(UpdateApiOp), - "UpdateApiOp")); - MAPPINGS.Add(new ObjectTypeMapperImpl(typeof(DeleteApiOp), - "DeleteApiOp")); - MAPPINGS.Add(new ObjectTypeMapperImpl(typeof(GetApiOp), - "GetApiOp")); - MAPPINGS.Add(new ObjectTypeMapperImpl(typeof(TestApiOp), - "TestApiOp")); - MAPPINGS.Add(new ObjectTypeMapperImpl(typeof(ScriptOnConnectorApiOp), - "ScriptOnConnectorApiOp")); - MAPPINGS.Add(new ObjectTypeMapperImpl(typeof(ScriptOnResourceApiOp), - "ScriptOnResourceApiOp")); - MAPPINGS.Add(new ObjectTypeMapperImpl(typeof(SyncApiOp), - "SyncApiOp")); - } - - } - #endregion - - #region CommonObjectHandlers - internal static class CommonObjectHandlers - { - public static readonly IList HANDLERS = - new List(); - static CommonObjectHandlers() - { - HANDLERS.Add(new AlreadyExistsExceptionHandler()); - HANDLERS.Add(new ConfigurationExceptionHandler()); - HANDLERS.Add(new ConnectionBrokenExceptionHandler()); - HANDLERS.Add(new ConnectionFailedExceptionHandler()); - HANDLERS.Add(new ConnectorIOExceptionHandler()); - HANDLERS.Add(new PasswordExpiredExceptionHandler()); - HANDLERS.Add(new InvalidPasswordExceptionHandler()); - HANDLERS.Add(new UnknownUidExceptionHandler()); - HANDLERS.Add(new InvalidCredentialExceptionHandler()); - HANDLERS.Add(new PermissionDeniedExceptionHandler()); - HANDLERS.Add(new ConnectorSecurityExceptionHandler()); - HANDLERS.Add(new OperationTimeoutExceptionHandler()); - HANDLERS.Add(new ConnectorExceptionHandler()); - HANDLERS.Add(new ArgumentExceptionHandler()); - HANDLERS.Add(new RuntimeExceptionHandler()); - HANDLERS.Add(new ExceptionHandler()); - HANDLERS.Add(new ThrowableHandler()); - HANDLERS.Add(new AttributeHandler()); - HANDLERS.Add(new AttributeInfoHandler()); - HANDLERS.Add(new ConnectorObjectHandler()); - HANDLERS.Add(new NameHandler()); - HANDLERS.Add(new ObjectClassHandler()); - HANDLERS.Add(new ObjectClassInfoHandler()); - HANDLERS.Add(new SchemaHandler()); - HANDLERS.Add(new UidHandler()); - HANDLERS.Add(new ScriptHandler()); - HANDLERS.Add(new ScriptContextHandler()); - HANDLERS.Add(new OperationOptionsHandler()); - HANDLERS.Add(new OperationOptionInfoHandler()); - HANDLERS.Add(new EnumSerializationHandler(typeof(ConnectorAttributeInfo.Flags), - "AttributeInfoFlag")); - HANDLERS.Add(new EnumSerializationHandler(typeof(SyncDeltaType), - "SyncDeltaType")); - HANDLERS.Add(new SyncTokenHandler()); - HANDLERS.Add(new SyncDeltaHandler()); - HANDLERS.Add(new QualifiedUidHandler()); - } - - private class AlreadyExistsExceptionHandler : AbstractExceptionHandler - { - public AlreadyExistsExceptionHandler() - : base("AlreadyExistsException") - { - - } - protected override AlreadyExistsException CreateException(String msg) - { - return new AlreadyExistsException(msg); - } - } - private class ConfigurationExceptionHandler : AbstractExceptionHandler - { - public ConfigurationExceptionHandler() - : base("ConfigurationException") - { - - } - protected override ConfigurationException CreateException(String msg) - { - return new ConfigurationException(msg); - } - } - private class ConnectionBrokenExceptionHandler : AbstractExceptionHandler - { - public ConnectionBrokenExceptionHandler() - : base("ConnectionBrokenException") - { - - } - protected override ConnectionBrokenException CreateException(String msg) - { - return new ConnectionBrokenException(msg); - } - } - private class ConnectionFailedExceptionHandler : AbstractExceptionHandler - { - public ConnectionFailedExceptionHandler() - : base("ConnectionFailedException") - { - - } - protected override ConnectionFailedException CreateException(String msg) - { - return new ConnectionFailedException(msg); - } - } - private class ConnectorIOExceptionHandler : AbstractExceptionHandler - { - public ConnectorIOExceptionHandler() - : base("ConnectorIOException") - { - - } - protected override ConnectorIOException CreateException(String msg) - { - return new ConnectorIOException(msg); - } - } - private class PasswordExpiredExceptionHandler : AbstractExceptionHandler - { - public PasswordExpiredExceptionHandler() - : base("PasswordExpiredException") - { - - } - - public override Object Deserialize(ObjectDecoder decoder) - { - Uid uid = (Uid)decoder.ReadObjectField("Uid", typeof(Uid), null); - PasswordExpiredException ex = - (PasswordExpiredException)base.Deserialize(decoder); - ex.Uid = uid; - return ex; - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - base.Serialize(obj, encoder); - PasswordExpiredException val = (PasswordExpiredException)obj; - encoder.WriteObjectField("Uid", val.Uid, true); - } - protected override PasswordExpiredException CreateException(String msg) - { - return new PasswordExpiredException(msg); - } - } - private class InvalidPasswordExceptionHandler : AbstractExceptionHandler - { - public InvalidPasswordExceptionHandler() - : base("InvalidPasswordException") - { - - } - protected override InvalidPasswordException CreateException(String msg) - { - return new InvalidPasswordException(msg); - } - } - private class UnknownUidExceptionHandler : AbstractExceptionHandler - { - public UnknownUidExceptionHandler() - : base("UnknownUidException") - { - - } - protected override UnknownUidException CreateException(String msg) - { - return new UnknownUidException(msg); - } - } - private class InvalidCredentialExceptionHandler : AbstractExceptionHandler - { - public InvalidCredentialExceptionHandler() - : base("InvalidCredentialException") - { - - } - protected override InvalidCredentialException CreateException(String msg) - { - return new InvalidCredentialException(msg); - } - } - private class PermissionDeniedExceptionHandler : AbstractExceptionHandler - { - public PermissionDeniedExceptionHandler() - : base("PermissionDeniedException") - { - - } - protected override PermissionDeniedException CreateException(String msg) - { - return new PermissionDeniedException(msg); - } - } - private class ConnectorSecurityExceptionHandler : AbstractExceptionHandler - { - public ConnectorSecurityExceptionHandler() - : base("ConnectorSecurityException") - { - - } - protected override ConnectorSecurityException CreateException(String msg) - { - return new ConnectorSecurityException(msg); - } - } - private class OperationTimeoutExceptionHandler : AbstractExceptionHandler - { - public OperationTimeoutExceptionHandler() - : base("OperationTimeoutException") - { - - } - protected override OperationTimeoutException CreateException(String msg) - { - return new OperationTimeoutException(msg); - } - } - private class ConnectorExceptionHandler : AbstractExceptionHandler - { - public ConnectorExceptionHandler() - : base("ConnectorException") - { - - } - protected override ConnectorException CreateException(String msg) - { - return new ConnectorException(msg); - } - } - //RuntimeException, Exception, and Throwable - //when going from Java to C#, these always become - //Exception. - //when going from C# to Java, these always become - //RuntimeException - private class RuntimeExceptionHandler : AbstractExceptionHandler - { - public RuntimeExceptionHandler() - : base("RuntimeException") - { - - } - protected override Exception CreateException(String msg) - { - return new Exception(msg); - } - } - - private class ArgumentExceptionHandler : AbstractExceptionHandler - { - public ArgumentExceptionHandler() - : base("IllegalArgumentException") - { - - } - protected override ArgumentException CreateException(string msg) - { - return new ArgumentException(msg); - } - } - - private class ExceptionHandler : AbstractExceptionHandler - { - public ExceptionHandler() - : base("Exception") - { - - } - protected override Exception CreateException(String msg) - { - return new Exception(msg); - } - } - private class ThrowableHandler : AbstractExceptionHandler - { - public ThrowableHandler() - : base("Throwable") - { - - } - protected override Exception CreateException(String msg) - { - return new Exception(msg); - } - } - - private abstract class AbstractAttributeHandler - : AbstractObjectSerializationHandler - where T : ConnectorAttribute - { - - protected AbstractAttributeHandler(String typeName) - : base(typeof(T), typeName) - { - } - - - public override sealed Object Deserialize(ObjectDecoder decoder) - { - String name = decoder.ReadStringField("name", null); - IList val = (IList)decoder.ReadObjectField("Values", typeof(IList), null); - return CreateAttribute(name, val); - } - - public override sealed void Serialize(Object obj, ObjectEncoder encoder) - { - ConnectorAttribute val = (ConnectorAttribute)obj; - encoder.WriteStringField("name", val.Name); - encoder.WriteObjectField("Values", val.Value, true); - } - - protected abstract T CreateAttribute(String name, IList val); - } - - private class AttributeHandler - : AbstractAttributeHandler - { - public AttributeHandler() - : base("Attribute") - { - - } - protected override ConnectorAttribute CreateAttribute(String name, IList value) - { - return ConnectorAttributeBuilder.Build(name, value); - } - } - - private class AttributeInfoHandler : AbstractObjectSerializationHandler - { - public AttributeInfoHandler() - : base(typeof(ConnectorAttributeInfo), "AttributeInfo") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - ConnectorAttributeInfoBuilder builder = new ConnectorAttributeInfoBuilder(); - builder.Name = ( - decoder.ReadStringField("name", null)); - builder.ValueType = ( - decoder.ReadClassField("type", null)); - ConnectorAttributeInfo.Flags flags = ConnectorAttributeInfo.Flags.NONE; - int count = decoder.GetNumSubObjects(); - for (int i = 0; i < count; i++) - { - object o = decoder.ReadObjectContents(i); - if (o is ConnectorAttributeInfo.Flags) - { - ConnectorAttributeInfo.Flags f = - (ConnectorAttributeInfo.Flags)o; - flags |= f; - } - } - builder.InfoFlags = flags; - return builder.Build(); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - ConnectorAttributeInfo val = (ConnectorAttributeInfo)obj; - encoder.WriteStringField("name", val.Name); - encoder.WriteClassField("type", val.ValueType); - ConnectorAttributeInfo.Flags flags = val.InfoFlags; - foreach (Enum e in Enum.GetValues(typeof(ConnectorAttributeInfo.Flags))) - { - ConnectorAttributeInfo.Flags flag = - (ConnectorAttributeInfo.Flags)e; - if ((flags & flag) != 0) - { - encoder.WriteObjectContents(flag); - } - } - } - } - - private class ConnectorObjectHandler : AbstractObjectSerializationHandler - { - public ConnectorObjectHandler() - : base(typeof(ConnectorObject), "ConnectorObject") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - ObjectClass oclass = - (ObjectClass)decoder.ReadObjectField("ObjectClass", typeof(ObjectClass), null); - ICollection attsObj = - (ICollection)decoder.ReadObjectField("Attributes", typeof(ICollection), null); - ICollection atts = - CollectionUtil.NewSet(attsObj); - return new ConnectorObject(oclass, atts); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - ConnectorObject val = (ConnectorObject)obj; - encoder.WriteObjectField("ObjectClass", val.ObjectClass, true); - encoder.WriteObjectField("Attributes", val.GetAttributes(), true); - } - } - private class NameHandler - : AbstractObjectSerializationHandler - { - public NameHandler() - : base(typeof(Name), "Name") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - String str = decoder.ReadStringContents(); - return new Name(str); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - Name val = (Name)obj; - encoder.WriteStringContents(val.GetNameValue()); - } - } - private class ObjectClassHandler : AbstractObjectSerializationHandler - { - public ObjectClassHandler() - : base(typeof(ObjectClass), "ObjectClass") - { - - } - public override object Deserialize(ObjectDecoder decoder) - { - string type = decoder.ReadStringField("type", null); - return new ObjectClass(type); - } - - public override void Serialize(object obj, ObjectEncoder encoder) - { - ObjectClass val = (ObjectClass)obj; - encoder.WriteStringField("type", val.GetObjectClassValue()); - } - } - - private class ObjectClassInfoHandler : AbstractObjectSerializationHandler - { - public ObjectClassInfoHandler() - : base(typeof(ObjectClassInfo), "ObjectClassInfo") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - string type = - decoder.ReadStringField("type", null); - bool container = - decoder.ReadBooleanField("container", false); - - ICollection attrInfoObj = - (ICollection)decoder.ReadObjectField("AttributeInfos", typeof(ICollection), null); - - ICollection attrInfo = - CollectionUtil.NewSet(attrInfoObj); - - return new ObjectClassInfo(type, attrInfo, container); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - ObjectClassInfo val = (ObjectClassInfo)obj; - encoder.WriteStringField("type", val.ObjectType); - encoder.WriteBooleanField("container", val.IsContainer); - encoder.WriteObjectField("AttributeInfos", val.ConnectorAttributeInfos, true); - } - } - private class SchemaHandler : AbstractObjectSerializationHandler - { - public SchemaHandler() - : base(typeof(Schema), "Schema") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - - ICollection objectClassesObj = - (ICollection)decoder.ReadObjectField("ObjectClassInfos", typeof(ICollection), null); - ICollection objectClasses = - CollectionUtil.NewSet(objectClassesObj); - IDictionary objectClassesByName = new Dictionary(); - foreach (ObjectClassInfo info in objectClasses) - { - objectClassesByName[info.ObjectType] = info; - } - ICollection operationOptionsObj = - (ICollection)decoder.ReadObjectField("OperationOptionInfos", typeof(ICollection), null); - ICollection operationOptions = - CollectionUtil.NewSet(operationOptionsObj); - IDictionary optionsByName = new Dictionary(); - foreach (OperationOptionInfo info in operationOptions) - { - optionsByName[info.Name] = info; - } - IDictionary objectClassNamesByOperationObj = - (IDictionary)decoder.ReadObjectField("objectClassesByOperation", null, null); - IDictionary, ICollection> - objectClassesByOperation = - new Dictionary, ICollection>(); - foreach (KeyValuePair entry in objectClassNamesByOperationObj) - { - SafeType op = SafeType.ForRawType((Type)entry.Key); - ICollection namesObj = - (ICollection)entry.Value; - ICollection infos = - new HashSet(); - foreach (object name in namesObj) - { - ObjectClassInfo objectClass = CollectionUtil.GetValue(objectClassesByName, (string)name, null); - if (objectClass != null) - { - infos.Add(objectClass); - } - } - objectClassesByOperation[op] = infos; - } - IDictionary optionsByOperationObj = - (IDictionary)decoder.ReadObjectField("optionsByOperation", null, null); - IDictionary, ICollection> - optionsByOperation = - new Dictionary, ICollection>(); - foreach (KeyValuePair entry in optionsByOperationObj) - { - SafeType op = SafeType.ForRawType((Type)entry.Key); - ICollection namesObj = - (ICollection)entry.Value; - ICollection infos = - new HashSet(); - foreach (object name in namesObj) - { - OperationOptionInfo info = CollectionUtil.GetValue(optionsByName, (string)name, null); - if (info != null) - { - infos.Add(info); - } - } - optionsByOperation[op] = infos; - } - return new Schema(objectClasses, - operationOptions, - objectClassesByOperation, - optionsByOperation); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - Schema val = (Schema)obj; - encoder.WriteObjectField("ObjectClassInfos", val.ObjectClassInfo, true); - encoder.WriteObjectField("OperationOptionInfos", val.OperationOptionInfo, true); - IDictionary> - objectClassNamesByOperation = new Dictionary>(); - IDictionary> - optionNamesByOperation = new Dictionary>(); - - - foreach (KeyValuePair, ICollection> - entry in val.SupportedObjectClassesByOperation) - { - ICollection value = entry.Value; - ICollection names = new HashSet(); - foreach (ObjectClassInfo info in value) - { - names.Add(info.ObjectType); - } - objectClassNamesByOperation[entry.Key.RawType] = names; - } - foreach (KeyValuePair, ICollection> - entry in val.SupportedOptionsByOperation) - { - ICollection value = entry.Value; - ICollection names = new HashSet(); - foreach (OperationOptionInfo info in value) - { - names.Add(info.Name); - } - optionNamesByOperation[entry.Key.RawType] = names; - } - encoder.WriteObjectField("objectClassesByOperation", objectClassNamesByOperation, false); - encoder.WriteObjectField("optionsByOperation", optionNamesByOperation, false); - } - } - private class UidHandler - : AbstractObjectSerializationHandler - { - public UidHandler() - : base(typeof(Uid), "Uid") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - String str = decoder.ReadStringContents(); - return new Uid(str); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - Uid val = (Uid)obj; - encoder.WriteStringContents(val.GetUidValue()); - } - } - private class ScriptHandler : AbstractObjectSerializationHandler - { - public ScriptHandler() - : base(typeof(Script), "Script") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - ScriptBuilder builder = new ScriptBuilder(); - builder.ScriptLanguage = decoder.ReadStringField("scriptLanguage", null); - builder.ScriptText = (String)decoder.ReadObjectField("scriptText", typeof(string), null); - return builder.Build(); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - Script val = (Script)obj; - encoder.WriteStringField("scriptLanguage", val.ScriptLanguage); - encoder.WriteObjectField("scriptText", val.ScriptText, true); - } - } - private class ScriptContextHandler : AbstractObjectSerializationHandler - { - public ScriptContextHandler() - : base(typeof(ScriptContext), "ScriptContext") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - String scriptLanguage = - decoder.ReadStringField("scriptLanguage", null); - IDictionary arguments = - (IDictionary)decoder.ReadObjectField("scriptArguments", null, null); - String scriptText = - (String)decoder.ReadObjectField("scriptText", typeof(string), null); - IDictionary arguments2 = - CollectionUtil.NewDictionary(arguments); - return new ScriptContext(scriptLanguage, scriptText, arguments2); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - ScriptContext val = (ScriptContext)obj; - encoder.WriteStringField("scriptLanguage", val.ScriptLanguage); - encoder.WriteObjectField("scriptArguments", val.ScriptArguments, false); - encoder.WriteObjectField("scriptText", val.ScriptText, true); - } - } - private class OperationOptionsHandler : AbstractObjectSerializationHandler - { - public OperationOptionsHandler() - : base(typeof(OperationOptions), "OperationOptions") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - IDictionary options = - (IDictionary)decoder.ReadObjectField("options", null, null); - IDictionary options2 = - CollectionUtil.NewDictionary(options); - return new OperationOptions(options2); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - OperationOptions val = (OperationOptions)obj; - encoder.WriteObjectField("options", val.Options, false); - } - } - private class OperationOptionInfoHandler : AbstractObjectSerializationHandler - { - public OperationOptionInfoHandler() - : base(typeof(OperationOptionInfo), "OperationOptionInfo") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - String name = decoder.ReadStringField("name", null); - Type type = decoder.ReadClassField("type", null); - return new OperationOptionInfo(name, type); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - OperationOptionInfo val = (OperationOptionInfo)obj; - encoder.WriteStringField("name", val.Name); - encoder.WriteClassField("type", val.OptionType); - } - } - private class SyncTokenHandler : AbstractObjectSerializationHandler - { - public SyncTokenHandler() - : base(typeof(SyncToken), "SyncToken") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - Object value = decoder.ReadObjectField("value", null, null); - return new SyncToken(value); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - SyncToken val = (SyncToken)obj; - encoder.WriteObjectField("value", val.Value, false); - } - } - private class SyncDeltaHandler : AbstractObjectSerializationHandler - { - public SyncDeltaHandler() - : base(typeof(SyncDelta), "SyncDelta") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - SyncDeltaBuilder builder = new SyncDeltaBuilder(); - builder.DeltaType = ((SyncDeltaType)decoder.ReadObjectField("SyncDeltaType", typeof(SyncDeltaType), null)); - builder.Token = ((SyncToken)decoder.ReadObjectField("SyncToken", typeof(SyncToken), null)); - builder.PreviousUid = ((Uid)decoder.ReadObjectField("PreviousUid", typeof(Uid), null)); - builder.Uid = ((Uid)decoder.ReadObjectField("Uid", typeof(Uid), null)); - builder.Object = ((ConnectorObject)decoder.ReadObjectField("ConnectorObject", typeof(ConnectorObject), null)); - return builder.Build(); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - SyncDelta val = (SyncDelta)obj; - encoder.WriteObjectField("SyncDeltaType", val.DeltaType, true); - encoder.WriteObjectField("SyncToken", val.Token, true); - encoder.WriteObjectField("PreviousUid", val.PreviousUid, true); - encoder.WriteObjectField("Uid", val.Uid, true); - encoder.WriteObjectField("ConnectorObject", val.Object, true); - } - } - private class QualifiedUidHandler : AbstractObjectSerializationHandler - { - public QualifiedUidHandler() - : base(typeof(QualifiedUid), "QualifiedUid") - { - - } - public override Object Deserialize(ObjectDecoder decoder) - { - ObjectClass objectClass = (ObjectClass)decoder.ReadObjectField("ObjectClass", typeof(ObjectClass), null); - Uid uid = (Uid)decoder.ReadObjectField("Uid", typeof(Uid), null); - return new QualifiedUid(objectClass, uid); - } - - public override void Serialize(Object obj, ObjectEncoder encoder) - { - QualifiedUid val = (QualifiedUid)obj; - encoder.WriteObjectField("ObjectClass", val.ObjectClass, true); - encoder.WriteObjectField("Uid", val.Uid, true); - } - } - } - #endregion - - #region FilterHandlers - internal static class FilterHandlers - { - public static readonly IList HANDLERS = - new List(); - static FilterHandlers() - { - HANDLERS.Add(new AndFilterHandler()); - HANDLERS.Add(new ContainsFilterHandler()); - HANDLERS.Add(new EndsWithFilterHandler()); - HANDLERS.Add(new EqualsFilterHandler()); - HANDLERS.Add(new GreaterThanFilterHandler()); - HANDLERS.Add(new GreaterThanOrEqualFilterHandler()); - HANDLERS.Add(new LessThanFilterHandler()); - HANDLERS.Add(new LessThanOrEqualFilterHandler()); - HANDLERS.Add(new NotFilterHandler()); - HANDLERS.Add(new OrFilterHandler()); - HANDLERS.Add(new StartsWithFilterHandler()); - HANDLERS.Add(new ContainsAllValuesFilterHandler()); - } - - private abstract class CompositeFilterHandler - : AbstractObjectSerializationHandler - where T : CompositeFilter - { - - protected CompositeFilterHandler(String typeName) - : base(typeof(T), typeName) - { - } - - - public override sealed Object Deserialize(ObjectDecoder decoder) - { - Filter left = (Filter)decoder.ReadObjectContents(0); - Filter right = (Filter)decoder.ReadObjectContents(1); - return CreateFilter(left, right); - } - - public override sealed void Serialize(Object obj, ObjectEncoder encoder) - { - CompositeFilter val = (CompositeFilter)obj; - encoder.WriteObjectContents(val.Left); - encoder.WriteObjectContents(val.Right); - } - - protected abstract T CreateFilter(Filter left, Filter right); - } - - private abstract class AttributeFilterHandler - : AbstractObjectSerializationHandler - where T : AttributeFilter - { - - protected AttributeFilterHandler(String typeName) - : base(typeof(T), typeName) - { - } - - - public override sealed Object Deserialize(ObjectDecoder decoder) - { - ConnectorAttribute attribute = (ConnectorAttribute)decoder.ReadObjectField("attribute", null, null); - return CreateFilter(attribute); - } - - public override sealed void Serialize(Object obj, ObjectEncoder encoder) - { - AttributeFilter val = (AttributeFilter)obj; - encoder.WriteObjectField("attribute", val.GetAttribute(), false); - } - - protected abstract T CreateFilter(ConnectorAttribute attribute); - } - - - - - private class AndFilterHandler : CompositeFilterHandler - { - public AndFilterHandler() - : base("AndFilter") - { - } - protected override AndFilter CreateFilter(Filter left, Filter right) - { - return new AndFilter(left, right); - } - } - - private class ContainsFilterHandler : AttributeFilterHandler - { - public ContainsFilterHandler() - : base("ContainsFilter") - { - } - protected override ContainsFilter CreateFilter(ConnectorAttribute attribute) - { - return new ContainsFilter(attribute); - } - } - - private class EndsWithFilterHandler : AttributeFilterHandler - { - public EndsWithFilterHandler() - : base("EndsWithFilter") - { - } - protected override EndsWithFilter CreateFilter(ConnectorAttribute attribute) - { - return new EndsWithFilter(attribute); - } - } - - private class EqualsFilterHandler : AttributeFilterHandler - { - public EqualsFilterHandler() - : base("EqualsFilter") - { - } - protected override EqualsFilter CreateFilter(ConnectorAttribute attribute) - { - return new EqualsFilter(attribute); - } - } - - private class GreaterThanFilterHandler : AttributeFilterHandler - { - public GreaterThanFilterHandler() - : base("GreaterThanFilter") - { - } - protected override GreaterThanFilter CreateFilter(ConnectorAttribute attribute) - { - return new GreaterThanFilter(attribute); - } - } - - private class GreaterThanOrEqualFilterHandler : AttributeFilterHandler - { - public GreaterThanOrEqualFilterHandler() - : base("GreaterThanOrEqualFilter") - { - } - protected override GreaterThanOrEqualFilter CreateFilter(ConnectorAttribute attribute) - { - return new GreaterThanOrEqualFilter(attribute); - } - } - private class LessThanFilterHandler : AttributeFilterHandler - { - public LessThanFilterHandler() - : base("LessThanFilter") - { - } - protected override LessThanFilter CreateFilter(ConnectorAttribute attribute) - { - return new LessThanFilter(attribute); - } - } - private class LessThanOrEqualFilterHandler : AttributeFilterHandler - { - public LessThanOrEqualFilterHandler() - : base("LessThanOrEqualFilter") - { - } - protected override LessThanOrEqualFilter CreateFilter(ConnectorAttribute attribute) - { - return new LessThanOrEqualFilter(attribute); - } - } - private class NotFilterHandler - : AbstractObjectSerializationHandler - { - - public NotFilterHandler() - : base(typeof(NotFilter), "NotFilter") - { - } - - - public override sealed Object Deserialize(ObjectDecoder decoder) - { - Filter filter = - (Filter)decoder.ReadObjectContents(0); - return new NotFilter(filter); - } - - public override sealed void Serialize(Object obj, ObjectEncoder encoder) - { - NotFilter val = (NotFilter)obj; - encoder.WriteObjectContents(val.Filter); - } - - } - private class OrFilterHandler : CompositeFilterHandler - { - public OrFilterHandler() - : base("OrFilter") - { - } - protected override OrFilter CreateFilter(Filter left, Filter right) - { - return new OrFilter(left, right); - } - } - private class StartsWithFilterHandler : AttributeFilterHandler - { - public StartsWithFilterHandler() - : base("StartsWithFilter") - { - } - protected override StartsWithFilter CreateFilter(ConnectorAttribute attribute) - { - return new StartsWithFilter(attribute); - } - } - - private class ContainsAllValuesFilterHandler : AttributeFilterHandler - { - public ContainsAllValuesFilterHandler() - : base("ContainsAllValuesFilter") - { - } - protected override ContainsAllValuesFilter CreateFilter(ConnectorAttribute attribute) - { - return new ContainsAllValuesFilter(attribute); - } - } - } - #endregion - - #region MessageHandlers - internal static class MessageHandlers - { - public static readonly IList HANDLERS = - new List(); - static MessageHandlers() - { - HANDLERS.Add(new HelloRequestHandler()); - HANDLERS.Add(new HelloResponseHandler()); - HANDLERS.Add(new OperationRequestHandler()); - HANDLERS.Add(new OperationResponseEndHandler()); - HANDLERS.Add(new OperationResponsePartHandler()); - HANDLERS.Add(new OperationRequestMoreDataHandler()); - HANDLERS.Add(new OperationRequestStopDataHandler()); - HANDLERS.Add(new OperationResponsePauseHandler()); - HANDLERS.Add(new EchoMessageHandler()); - } - private class HelloRequestHandler - : AbstractObjectSerializationHandler - { - - public HelloRequestHandler() - : base(typeof(HelloRequest), "HelloRequest") - { - } - - - public override sealed Object Deserialize(ObjectDecoder decoder) - { - return new HelloRequest(); - } - - public override sealed void Serialize(Object obj, ObjectEncoder encoder) - { - } - - } - private class HelloResponseHandler - : AbstractObjectSerializationHandler - { - - public HelloResponseHandler() - : base(typeof(HelloResponse), "HelloResponse") - { - } - - - public override sealed Object Deserialize(ObjectDecoder decoder) - { - Exception exception = - (Exception)decoder.ReadObjectField("exception", null, null); - IList connectorInfosObj = - (IList)decoder.ReadObjectField("ConnectorInfos", typeof(IList), null); - IList connectorInfos = - CollectionUtil.NewList(connectorInfosObj); - return new HelloResponse(exception, connectorInfos); - } - - public override sealed void Serialize(Object obj, ObjectEncoder encoder) - { - HelloResponse val = (HelloResponse)obj; - encoder.WriteObjectField("exception", val.Exception, false); - encoder.WriteObjectField("ConnectorInfos", val.ConnectorInfos, true); - } - - } - private class OperationRequestHandler - : AbstractObjectSerializationHandler - { - - public OperationRequestHandler() - : base(typeof(OperationRequest), "OperationRequest") - { - } - - - public override sealed Object Deserialize(ObjectDecoder decoder) - { - ConnectorKey connectorKey = - (ConnectorKey)decoder.ReadObjectField("ConnectorKey", typeof(ConnectorKey), null); - APIConfigurationImpl configuration = - (APIConfigurationImpl)decoder.ReadObjectField("APIConfiguration", typeof(APIConfigurationImpl), null); - Type operation = - decoder.ReadClassField("operation", null); - string operationMethodName = - decoder.ReadStringField("operationMethodName", null); - IList arguments = (IList) - decoder.ReadObjectField("Arguments", typeof(IList), null); - return new OperationRequest(connectorKey, - configuration, - SafeType.ForRawType(operation), - operationMethodName, - arguments); - } - - public override sealed void Serialize(Object obj, ObjectEncoder encoder) - { - OperationRequest val = - (OperationRequest)obj; - encoder.WriteClassField("operation", - val.Operation.RawType); - encoder.WriteStringField("operationMethodName", - val.OperationMethodName); - encoder.WriteObjectField("ConnectorKey", - val.ConnectorKey, true); - encoder.WriteObjectField("APIConfiguration", - val.Configuration, true); - encoder.WriteObjectField("Arguments", - val.Arguments, true); - } - - } - private class OperationResponseEndHandler - : AbstractObjectSerializationHandler - { - - public OperationResponseEndHandler() - : base(typeof(OperationResponseEnd), "OperationResponseEnd") - { - } - - - public override sealed Object Deserialize(ObjectDecoder decoder) - { - return new OperationResponseEnd(); - } - - public override sealed void Serialize(Object obj, ObjectEncoder encoder) - { - } - } - private class OperationResponsePartHandler - : AbstractObjectSerializationHandler - { - - public OperationResponsePartHandler() - : base(typeof(OperationResponsePart), "OperationResponsePart") - { - } - - - public override sealed Object Deserialize(ObjectDecoder decoder) - { - Exception exception = - (Exception)decoder.ReadObjectField("exception", null, null); - Object result = - decoder.ReadObjectField("result", null, null); - - return new OperationResponsePart(exception, result); - } - - public override sealed void Serialize(Object obj, ObjectEncoder encoder) - { - OperationResponsePart val = (OperationResponsePart)obj; - encoder.WriteObjectField("exception", val.Exception, false); - encoder.WriteObjectField("result", val.Result, false); - } - } - private class OperationRequestMoreDataHandler - : AbstractObjectSerializationHandler - { - - public OperationRequestMoreDataHandler() - : base(typeof(OperationRequestMoreData), "OperationRequestMoreData") - { - } - - - public override sealed Object Deserialize(ObjectDecoder decoder) - { - return new OperationRequestMoreData(); - } - - public override sealed void Serialize(Object obj, ObjectEncoder encoder) - { - } - } - private class OperationRequestStopDataHandler - : AbstractObjectSerializationHandler - { - - public OperationRequestStopDataHandler() - : base(typeof(OperationRequestStopData), "OperationRequestStopData") - { - } - - - public override sealed Object Deserialize(ObjectDecoder decoder) - { - return new OperationRequestStopData(); - } - - public override sealed void Serialize(Object obj, ObjectEncoder encoder) - { - } - } - private class OperationResponsePauseHandler - : AbstractObjectSerializationHandler - { - - public OperationResponsePauseHandler() - : base(typeof(OperationResponsePause), "OperationResponsePause") - { - } - - - public override sealed Object Deserialize(ObjectDecoder decoder) - { - return new OperationResponsePause(); - } - - public override sealed void Serialize(Object obj, ObjectEncoder encoder) - { - } - } - private class EchoMessageHandler - : AbstractObjectSerializationHandler - { - - public EchoMessageHandler() - : base(typeof(EchoMessage), "EchoMessage") - { - } - - - public override sealed Object Deserialize(ObjectDecoder decoder) - { - return new EchoMessage(decoder.ReadObjectField("value", null, null), - (String)decoder.ReadObjectField("objectXml", typeof(string), null)); - } - - public override sealed void Serialize(Object obj, ObjectEncoder encoder) - { - EchoMessage val = (EchoMessage)obj; - encoder.WriteObjectField("value", val.Object, false); - encoder.WriteObjectField("objectXml", val.ObjectXml, true); - } - } - } - #endregion -} \ No newline at end of file diff --git a/FrameworkInternal/SerializerBinary.cs b/FrameworkInternal/SerializerBinary.cs deleted file mode 100644 index 20e19b2..0000000 --- a/FrameworkInternal/SerializerBinary.cs +++ /dev/null @@ -1,895 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Framework.Common.Exceptions; -using Org.IdentityConnectors.Framework.Common.Serializer; -using Org.IdentityConnectors.Framework.Impl.Serializer; -using System.IO; -using System.Text; -namespace Org.IdentityConnectors.Framework.Impl.Serializer.Binary -{ - internal class InternalEncoder - { - /// - /// Mapping from type name to the ID we serialize so we only have to - /// - private IDictionary _constantPool = - new Dictionary(); - - private IList _constantBuffer = new List(); - - private IList _outputBufferStack = new List(); - internal Stream _rootOutput; - private bool _firstObject = true; - - public InternalEncoder(Stream output) - { - _rootOutput = output; - } - - public void WriteObject(ObjectEncoder encoder, Object obj) - { - - if (_firstObject) - { - WriteInt(BinaryObjectEncoder.OBJECT_MAGIC); - WriteInt(BinaryObjectEncoder.ENCODING_VERSION); - _firstObject = false; - } - - MemoryStream objectBuffer = new MemoryStream(); - _outputBufferStack.Add(objectBuffer); - - if (obj == null) - { - WriteByte(BinaryObjectEncoder.OBJECT_TYPE_NULL); - } - else - { - Type clazz = obj.GetType(); - WriteClass(clazz); - ObjectSerializationHandler handler = - ObjectSerializerRegistry.GetHandlerByObjectType(clazz); - if (handler == null) - { - //we may have special handlers for certain types of arrays - //if handler is null, treat like any other array - if (obj is Array) - { - Array array = (Array)obj; - int length = array.Length; - for (int i = 0; i < length; i++) - { - Object val = array.GetValue(i); - StartAnonymousField(); - WriteObject(encoder, val); - EndField(); - } - } - else - { - throw new ConnectorException("No serializer for class: " + clazz); - } - } - else - { - handler.Serialize(obj, encoder); - } - } - - //write end-object into the current obj buffer - WriteByte(BinaryObjectEncoder.FIELD_TYPE_END_OBJECT); - - //pop the stack - _outputBufferStack.RemoveAt(_outputBufferStack.Count - 1); - - //it's a top-level object, flush the constant pool - if (_outputBufferStack.Count == 0) - { - WriteInt(_constantBuffer.Count); - foreach (String constant in _constantBuffer) - { - WriteString(constant, false); - WriteInt(_constantPool[constant]); - } - _constantBuffer.Clear(); - } - - //now write the actual object - objectBuffer.Close(); - byte[] bytes = objectBuffer.ToArray(); - WriteBytes(bytes); - } - - public void WriteClass(Type clazz) - { - ObjectSerializationHandler handler = - ObjectSerializerRegistry.GetHandlerByObjectType(clazz); - ObjectTypeMapper mapper = - ObjectSerializerRegistry.GetMapperByObjectType(clazz); - if (handler == null && clazz.IsArray) - { - //we may have special handlers for certain types of arrays - //if handler is null, treat like any other array - WriteByte(BinaryObjectEncoder.OBJECT_TYPE_ARRAY); - WriteClass(clazz.GetElementType()); - } - else if (mapper == null) - { - throw new ConnectorException("No serializer for class: " + clazz); - } - else - { - String typeName = mapper.HandledSerialType; - WriteByte(BinaryObjectEncoder.OBJECT_TYPE_CLASS); - WriteString(typeName, true); - } - } - - public void StartAnonymousField() - { - WriteByte(BinaryObjectEncoder.FIELD_TYPE_ANONYMOUS_FIELD); - MemoryStream buf = new MemoryStream(); - _outputBufferStack.Add(buf); - } - - public void StartField(String name) - { - WriteByte(BinaryObjectEncoder.FIELD_TYPE_NAMED_FIELD); - WriteString(name, true); - MemoryStream buf = new MemoryStream(); - _outputBufferStack.Add(buf); - } - - public void EndField() - { - MemoryStream buf = _outputBufferStack[_outputBufferStack.Count - 1]; - _outputBufferStack.RemoveAt(_outputBufferStack.Count - 1); - buf.Close(); - byte[] bytes = buf.ToArray(); - WriteByteArray(bytes); - } - - public void WriteInt(int v) - { - Stream output = GetCurrentOutput(); - output.WriteByte((byte)(0xff & (v >> 24))); - output.WriteByte((byte)(0xff & (v >> 16))); - output.WriteByte((byte)(0xff & (v >> 8))); - output.WriteByte((byte)(0xff & v)); - } - - public void WriteLong(long v) - { - Stream output = GetCurrentOutput(); - output.WriteByte((byte)(0xff & (v >> 56))); - output.WriteByte((byte)(0xff & (v >> 48))); - output.WriteByte((byte)(0xff & (v >> 40))); - output.WriteByte((byte)(0xff & (v >> 32))); - output.WriteByte((byte)(0xff & (v >> 24))); - output.WriteByte((byte)(0xff & (v >> 16))); - output.WriteByte((byte)(0xff & (v >> 8))); - output.WriteByte((byte)(0xff & v)); - } - - public void WriteDouble(double l) - { - long val = BitConverter.DoubleToInt64Bits(l); - WriteLong(val); - } - - public void WriteByteArray(byte[] v) - { - WriteInt(v.Length); - WriteBytes(v); - } - - public void WriteByte(byte b) - { - GetCurrentOutput().WriteByte(b); - } - - public void WriteBoolean(bool b) - { - WriteByte(b ? (byte)1 : (byte)0); - } - - public void WriteString(String str, bool intern) - { - if (intern) - { - int code = InternIdentifier(str); - WriteInt(code); - return; - } - byte[] bytes = Encoding.UTF8.GetBytes(str); - WriteByteArray(bytes); - } - - private int InternIdentifier(String name) - { - int code = CollectionUtil.GetValue(_constantPool, name, -1); - if (code == -1) - { - code = _constantPool.Count; - _constantPool[name] = code; - _constantBuffer.Add(name); - } - return code; - } - - private void WriteBytes(byte[] v) - { - //only write if length > 0 - C# seems to have a problem with - //zero-length byte arrays - if (v.Length > 0) - { - GetCurrentOutput().Write(v, 0, v.Length); - } - } - - private Stream GetCurrentOutput() - { - if (_outputBufferStack.Count == 0) - { - return _rootOutput; - } - else - { - MemoryStream buf = _outputBufferStack[_outputBufferStack.Count - 1]; - return buf; - } - } - } - - internal class BinaryObjectEncoder : ObjectEncoder, BinaryObjectSerializer - { - public const int ENCODING_VERSION = 1; - - public const int OBJECT_MAGIC = 0xFAFB; - - public const byte OBJECT_TYPE_NULL = 60; - public const byte OBJECT_TYPE_CLASS = 61; - public const byte OBJECT_TYPE_ARRAY = 62; - - public const byte FIELD_TYPE_ANONYMOUS_FIELD = 70; - public const byte FIELD_TYPE_NAMED_FIELD = 71; - public const byte FIELD_TYPE_END_OBJECT = 72; - - - private InternalEncoder _internalEncoder; - - public BinaryObjectEncoder(Stream output) - { - _internalEncoder = new InternalEncoder(new BufferedStream(output, 4096)); - } - - public void Flush() - { - _internalEncoder._rootOutput.Flush(); - } - - public void Close() - { - _internalEncoder._rootOutput.Close(); - } - - public void WriteObject(Object o) - { - _internalEncoder.WriteObject(this, o); - } - - public void WriteBooleanContents(bool v) - { - _internalEncoder.StartAnonymousField(); - _internalEncoder.WriteBoolean(v); - _internalEncoder.EndField(); - } - - public void WriteBooleanField(String fieldName, bool v) - { - _internalEncoder.StartField(fieldName); - _internalEncoder.WriteBoolean(v); - _internalEncoder.EndField(); - } - - public void WriteByteArrayContents(byte[] v) - { - _internalEncoder.StartAnonymousField(); - _internalEncoder.WriteByteArray(v); - _internalEncoder.EndField(); - } - - public void WriteClassContents(Type v) - { - _internalEncoder.StartAnonymousField(); - _internalEncoder.WriteClass(v); - _internalEncoder.EndField(); - } - - public void WriteClassField(string fieldName, Type v) - { - if (v != null) - { - _internalEncoder.StartField(fieldName); - _internalEncoder.WriteClass(v); - _internalEncoder.EndField(); - } - } - - public void WriteDoubleContents(double v) - { - _internalEncoder.StartAnonymousField(); - _internalEncoder.WriteDouble(v); - _internalEncoder.EndField(); - } - - public void WriteDoubleField(String fieldName, double v) - { - _internalEncoder.StartField(fieldName); - _internalEncoder.WriteDouble(v); - _internalEncoder.EndField(); - } - - public void WriteFloatContents(float v) - { - _internalEncoder.StartAnonymousField(); - //write as double since C# only knows how to deal with that - _internalEncoder.WriteDouble((double)v); - _internalEncoder.EndField(); - } - - public void WriteFloatField(String fieldName, float v) - { - _internalEncoder.StartField(fieldName); - //write as double since C# only knows how to deal with that - _internalEncoder.WriteDouble((double)v); - _internalEncoder.EndField(); - } - - public void WriteIntContents(int v) - { - _internalEncoder.StartAnonymousField(); - _internalEncoder.WriteInt(v); - _internalEncoder.EndField(); - } - - public void WriteIntField(String fieldName, int v) - { - _internalEncoder.StartField(fieldName); - _internalEncoder.WriteInt(v); - _internalEncoder.EndField(); - } - - public void WriteLongContents(long v) - { - _internalEncoder.StartAnonymousField(); - _internalEncoder.WriteLong(v); - _internalEncoder.EndField(); - } - - public void WriteLongField(String fieldName, long v) - { - _internalEncoder.StartField(fieldName); - _internalEncoder.WriteLong(v); - _internalEncoder.EndField(); - } - - public void WriteObjectContents(Object obj) - { - _internalEncoder.StartAnonymousField(); - _internalEncoder.WriteObject(this, obj); - _internalEncoder.EndField(); - } - - public void WriteObjectField(String fieldName, Object obj, bool inline) - { - _internalEncoder.StartField(fieldName); - _internalEncoder.WriteObject(this, obj); - _internalEncoder.EndField(); - } - - public void WriteStringContents(String str) - { - _internalEncoder.StartAnonymousField(); - _internalEncoder.WriteString(str, false); - _internalEncoder.EndField(); - } - - public void WriteStringField(String fieldName, String val) - { - if (val != null) - { - _internalEncoder.StartField(fieldName); - _internalEncoder.WriteString(val, false); - _internalEncoder.EndField(); - } - } - } - - internal class ReadState - { - public IDictionary objectFields = new Dictionary(); - public IList anonymousFields = new List(); - public Stream currentInput; - public ReadState() - { - } - public bool StartField(String name) - { - currentInput = null; - byte[] content = CollectionUtil.GetValue(objectFields, name, null); - if (content == null) - { - return false; - } - else - { - currentInput = new MemoryStream(content); - return true; - } - } - public void StartAnonymousField(int index) - { - if (index >= anonymousFields.Count) - { - throw new ConnectorException("Anonymous content not found"); - } - currentInput = new MemoryStream(anonymousFields[index]); - } - } - - internal class InternalDecoder - { - private readonly byte[] _int_buf = new byte[4]; - private readonly byte[] _long_buf = new byte[8]; - private readonly byte[] _byte_buf = new byte[1]; - - private bool _firstObject = true; - - private readonly IDictionary _constantPool = - new Dictionary(); - - private readonly IList _readStateStack = new List(); - internal readonly Stream _rootInput; - - public InternalDecoder(Stream input) - { - _rootInput = input; - } - - public Object ReadObject(ObjectDecoder decoder) - { - - if (_firstObject) - { - int magic = ReadInt(); - if (magic != BinaryObjectEncoder.OBJECT_MAGIC) - { - throw new ConnectorException("Bad magic number: " + magic); - } - int version = ReadInt(); - if (version != BinaryObjectEncoder.ENCODING_VERSION) - { - throw new ConnectorException("Unexpected version: " + version); - } - _firstObject = false; - } - - //if it's a top-level object, it's proceeded by a constant pool - if (_readStateStack.Count == 0) - { - int size = ReadInt(); - for (int i = 0; i < size; i++) - { - String constant = ReadString(false); - int code = ReadInt(); - _constantPool[code] = constant; - } - } - - Type clazz = ReadClass(); - - ReadState state = new ReadState(); - while (true) - { - byte type = ReadByte(); - if (type == BinaryObjectEncoder.FIELD_TYPE_END_OBJECT) - { - break; - } - else if (type == BinaryObjectEncoder.FIELD_TYPE_ANONYMOUS_FIELD) - { - byte[] bytes = ReadByteArray(); - state.anonymousFields.Add(bytes); - } - else if (type == BinaryObjectEncoder.FIELD_TYPE_NAMED_FIELD) - { - String fieldName = ReadString(true); - byte[] bytes = ReadByteArray(); - state.objectFields[fieldName] = bytes; - } - else - { - throw new ConnectorException("Unknown type: " + type); - } - } - _readStateStack.Add(state); - - Object rv; - if (clazz == null) - { - rv = null; - } - else - { - ObjectSerializationHandler handler = - ObjectSerializerRegistry.GetHandlerByObjectType(clazz); - if (handler == null) - { - //we may have special handlers for certain types of arrays - //if handler is null, treat like any other array - if (clazz.IsArray) - { - int length = GetNumAnonymousFields(); - Array array = Array.CreateInstance(clazz.GetElementType(), - length); - for (int i = 0; i < length; i++) - { - StartAnonymousField(i); - Object element = ReadObject(decoder); - array.SetValue(element, i); - } - rv = array; - } - else - { - throw new ConnectorException("No deserializer for type: " + clazz); - } - } - else - { - rv = handler.Deserialize(decoder); - } - } - _readStateStack.RemoveAt(_readStateStack.Count - 1); - return rv; - } - - public Type ReadClass() - { - int type = ReadByte(); - if (type == BinaryObjectEncoder.OBJECT_TYPE_NULL) - { - return null; - } - else if (type == BinaryObjectEncoder.OBJECT_TYPE_ARRAY) - { - Type componentClass = ReadClass(); - return componentClass.MakeArrayType(); - } - else if (type == BinaryObjectEncoder.OBJECT_TYPE_CLASS) - { - String typeName = ReadString(true); - ObjectTypeMapper mapper = - ObjectSerializerRegistry.GetMapperBySerialType(typeName); - if (mapper == null) - { - throw new ConnectorException("No deserializer for type: " + typeName); - } - return mapper.HandledObjectType; - } - else - { - throw new ConnectorException("Bad type value: " + type); - } - } - - public int GetNumAnonymousFields() - { - ReadState readState = _readStateStack[_readStateStack.Count - 1]; - return readState.anonymousFields.Count; - } - - public void StartAnonymousField(int index) - { - ReadState readState = _readStateStack[_readStateStack.Count - 1]; - readState.StartAnonymousField(index); - } - - public bool StartField(String name) - { - ReadState readState = _readStateStack[_readStateStack.Count - 1]; - return readState.StartField(name); - } - - public int ReadInt() - { - ReadByteArrayFully(_int_buf); - return (((_int_buf[0] & 0xff) << 24) | ((_int_buf[1] & 0xff) << 16) | - ((_int_buf[2] & 0xff) << 8) | (_int_buf[3] & 0xff)); - } - - public long ReadLong() - { - ReadByteArrayFully(_long_buf); - return (((long)(_long_buf[0] & 0xff) << 56) | - ((long)(_long_buf[1] & 0xff) << 48) | - ((long)(_long_buf[2] & 0xff) << 40) | - ((long)(_long_buf[3] & 0xff) << 32) | - ((long)(_long_buf[4] & 0xff) << 24) | - ((long)(_long_buf[5] & 0xff) << 16) | - ((long)(_long_buf[6] & 0xff) << 8) | - ((long)(_long_buf[7] & 0xff))); - } - - public double ReadDouble() - { - long v = ReadLong(); - return BitConverter.Int64BitsToDouble(v); - } - - public byte[] ReadByteArray() - { - int len = ReadInt(); - byte[] bytes = new byte[len]; - ReadByteArrayFully(bytes); - return bytes; - } - - public byte ReadByte() - { - ReadByteArrayFully(_byte_buf); - return _byte_buf[0]; - } - - public bool ReadBoolean() - { - byte b = ReadByte(); - return b != 0; - } - - public String ReadString(bool interned) - { - if (interned) - { - int code = ReadInt(); - String name = CollectionUtil.GetValue(_constantPool, code, null); - if (name == null) - { - throw new ConnectorException("Undeclared code: " + code); - } - return name; - } - byte[] bytes = ReadByteArray(); - return Encoding.UTF8.GetString(bytes); - } - - private Stream GetCurrentInput() - { - if (_readStateStack.Count > 0) - { - ReadState state = _readStateStack[_readStateStack.Count - 1]; - return state.currentInput; - } - else - { - return _rootInput; - } - } - - private void ReadByteArrayFully(byte[] bytes) - { - int pos = 0; - while (pos < bytes.Length) - { - int count = GetCurrentInput().Read(bytes, pos, bytes.Length - pos); - if (count <= 0) - { - throw new EndOfStreamException(); - } - pos += count; - } - } - } - - internal class BinaryObjectDecoder : ObjectDecoder, BinaryObjectDeserializer - { - - private InternalDecoder _internalDecoder; - - public BinaryObjectDecoder(Stream inp) - { - _internalDecoder = new InternalDecoder(new BufferedStream(inp, 4096)); - } - - public void Close() - { - _internalDecoder._rootInput.Close(); - } - - public Object ReadObject() - { - return _internalDecoder.ReadObject(this); - } - - public bool ReadBooleanContents() - { - _internalDecoder.StartAnonymousField(0); - return _internalDecoder.ReadBoolean(); - } - - public bool ReadBooleanField(String fieldName, bool dflt) - { - if (_internalDecoder.StartField(fieldName)) - { - return _internalDecoder.ReadBoolean(); - } - else - { - return dflt; - } - } - - public byte[] ReadByteArrayContents() - { - _internalDecoder.StartAnonymousField(0); - return _internalDecoder.ReadByteArray(); - } - - public Type ReadClassContents() - { - _internalDecoder.StartAnonymousField(0); - return _internalDecoder.ReadClass(); - } - - public Type ReadClassField(string fieldName, Type dflt) - { - if (_internalDecoder.StartField(fieldName)) - { - return _internalDecoder.ReadClass(); - } - else - { - return dflt; - } - } - - public double ReadDoubleContents() - { - _internalDecoder.StartAnonymousField(0); - return _internalDecoder.ReadDouble(); - } - - public double ReadDoubleField(String fieldName, double dflt) - { - if (_internalDecoder.StartField(fieldName)) - { - return ReadDoubleContents(); - } - else - { - return dflt; - } - } - - public float ReadFloatContents() - { - _internalDecoder.StartAnonymousField(0); - //read as double since C# only knows how to deal with that - return (float)_internalDecoder.ReadDouble(); - } - - public float ReadFloatField(String fieldName, float dflt) - { - if (_internalDecoder.StartField(fieldName)) - { - //read as double since C# only knows how to deal with that - return (float)_internalDecoder.ReadDouble(); - } - else - { - return dflt; - } - } - - public int ReadIntContents() - { - _internalDecoder.StartAnonymousField(0); - return _internalDecoder.ReadInt(); - } - - public int ReadIntField(String fieldName, int dflt) - { - if (_internalDecoder.StartField(fieldName)) - { - return _internalDecoder.ReadInt(); - } - else - { - return dflt; - } - } - - public long ReadLongContents() - { - _internalDecoder.StartAnonymousField(0); - return _internalDecoder.ReadLong(); - } - - public long ReadLongField(String fieldName, long dflt) - { - if (_internalDecoder.StartField(fieldName)) - { - return _internalDecoder.ReadLong(); - } - else - { - return dflt; - } - } - - public int GetNumSubObjects() - { - return _internalDecoder.GetNumAnonymousFields(); - } - - public Object ReadObjectContents(int index) - { - _internalDecoder.StartAnonymousField(index); - return _internalDecoder.ReadObject(this); - } - - public Object ReadObjectField(String fieldName, Type expected, Object dflt) - { - if (_internalDecoder.StartField(fieldName)) - { - return _internalDecoder.ReadObject(this); - } - else - { - return dflt; - } - } - - public String ReadStringContents() - { - _internalDecoder.StartAnonymousField(0); - return _internalDecoder.ReadString(false); - } - - public String ReadStringField(String fieldName, String dflt) - { - if (_internalDecoder.StartField(fieldName)) - { - return _internalDecoder.ReadString(false); - } - else - { - return dflt; - } - } - } -} \ No newline at end of file diff --git a/FrameworkInternal/SerializerXml.cs b/FrameworkInternal/SerializerXml.cs deleted file mode 100644 index 59d52a9..0000000 --- a/FrameworkInternal/SerializerXml.cs +++ /dev/null @@ -1,930 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.IO; -using System.Resources; -using System.Text; -using System.Net; -using System.Xml; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Framework.Common.Exceptions; -using Org.IdentityConnectors.Framework.Common.Serializer; -namespace Org.IdentityConnectors.Framework.Impl.Serializer.Xml -{ - public class XmlObjectEncoder : ObjectEncoder - { - private StringBuilder _rootBuilder; - private XmlWriter _writer; - - public XmlObjectEncoder(StringBuilder builder) - { - Assertions.NullCheck(builder, "builder"); - _rootBuilder = builder; - } - - public String WriteObject(Object o) - { - XmlWriterSettings settings = new XmlWriterSettings(); - settings.Indent = true; - settings.OmitXmlDeclaration = true; - _writer = XmlWriter.Create(_rootBuilder, settings); - String rv = WriteObjectInternal(o, false); - _writer.Close(); - return rv; - } - - public void WriteBooleanContents(bool v) - { - WriteStringContentsInternal(EncodeBoolean(v)); - } - - public void WriteBooleanField(String fieldName, bool v) - { - WriteAttributeInternal(fieldName, EncodeBoolean(v)); - } - - public void WriteByteArrayContents(byte[] v) - { - WriteStringContentsInternal(EncodeByteArray(v)); - } - - public void WriteClassContents(Type v) - { - WriteStringContentsInternal(EncodeClass(v)); - } - - public void WriteClassField(String name, Type v) - { - if (v != null) - { - WriteAttributeInternal(name, EncodeClass(v)); - } - } - - public void WriteDoubleContents(double v) - { - WriteStringContentsInternal(EncodeDouble(v)); - } - - public void WriteDoubleField(String fieldName, double v) - { - WriteAttributeInternal(fieldName, EncodeDouble(v)); - } - - public void WriteFloatContents(float v) - { - WriteStringContentsInternal(EncodeFloat(v)); - } - - public void WriteFloatField(String fieldName, float v) - { - WriteAttributeInternal(fieldName, EncodeFloat(v)); - } - - public void WriteIntContents(int v) - { - WriteStringContentsInternal(EncodeInt(v)); - } - - public void WriteIntField(String fieldName, int v) - { - WriteAttributeInternal(fieldName, EncodeInt(v)); - } - - public void WriteLongContents(long v) - { - WriteStringContentsInternal(EncodeLong(v)); - } - - public void WriteLongField(String fieldName, long v) - { - WriteAttributeInternal(fieldName, EncodeLong(v)); - } - - public void WriteObjectContents(Object o) - { - WriteObjectInternal(o, false); - } - - public void WriteObjectField(String fieldName, Object obj, bool inline) - { - if (inline && obj == null) - { - return; //don't write anything - } - BeginElement(fieldName); - WriteObjectInternal(obj, inline); - EndElement(); - } - - public void WriteStringContents(String str) - { - WriteStringContentsInternal(str); - } - - public void WriteStringField(String fieldName, String str) - { - if (str != null) - { - WriteAttributeInternal(fieldName, str); - } - } - - internal static String EncodeBoolean(bool b) - { - return b.ToString(); - } - - private static String EncodeByteArray(byte[] bytes) - { - return Convert.ToBase64String(bytes); - } - - private static String EncodeClass(Type clazz) - { - ObjectSerializationHandler handler = - ObjectSerializerRegistry.GetHandlerByObjectType(clazz); - ObjectTypeMapper mapper = - ObjectSerializerRegistry.GetMapperByObjectType(clazz); - if (handler == null && clazz.IsArray) - { - //we may have special handlers for certain types of arrays - //if handler is null, treat like any other array - return EncodeClass(clazz.GetElementType()) + "[]"; - } - else if (mapper == null) - { - throw new ConnectorException("No serializer for class: " + clazz); - } - else - { - String typeName = mapper.HandledSerialType; - return typeName; - } - } - - internal static String EncodeDouble(double d) - { - return d.ToString("R"); - } - - internal static String EncodeFloat(float d) - { - return d.ToString("R"); - } - - internal static String EncodeInt(int d) - { - return d.ToString(); - } - - internal static String EncodeLong(long d) - { - return d.ToString(); - } - - /// - /// Writes the object - /// - /// - /// - /// The type name (regardless of whether it was inlined) - String WriteObjectInternal(Object obj, bool inline) - { - if (obj == null) - { - if (inline) - { - throw new ArgumentException("null cannot be inlined"); - } - BeginElement("null"); - EndElement(); - return "null"; - } - else - { - Type clazz = obj.GetType(); - ObjectSerializationHandler handler = - ObjectSerializerRegistry.GetHandlerByObjectType(clazz); - if (handler == null) - { - //we may have special handlers for certain types of arrays - //if handler is null, treat like any other array - if (clazz.IsArray) - { - if (!inline) - { - String componentTypeName = EncodeClass(clazz.GetElementType()); - BeginElement("Array"); - WriteAttributeInternal("componentType", componentTypeName); - } - Array array = (Array)obj; - int length = array.Length; - for (int i = 0; i < length; i++) - { - Object val = array.GetValue(i); - WriteObjectInternal(val, false); - } - if (!inline) - { - EndElement(); - } - return "Array"; - } - else - { - throw new ConnectorException("No serializer for class: " + clazz); - } - } - else - { - String typeName = EncodeClass(clazz); - if (!inline) - { - BeginElement(typeName); - } - handler.Serialize(obj, this); - if (!inline) - { - EndElement(); - } - return typeName; - } - } - - } - - ////////////////////////////////////////////////////////////////// - // - // xml encoding - // - ///////////////////////////////////////////////////////////////// - - private void BeginElement(String name) - { - _writer.WriteStartElement(name); - } - - private void EndElement() - { - _writer.WriteEndElement(); - } - private void WriteAttributeInternal(String fieldName, String str) - { - _writer.WriteAttributeString(fieldName, str); - } - private void WriteStringContentsInternal(String str) - { - _writer.WriteString(str); - } - } - - public class XmlObjectDecoder : ObjectDecoder - { - - private readonly XmlElement _node; - private readonly Type _expectedClass; - - public XmlObjectDecoder(XmlElement node, Type expectedClass) - { - _node = node; - _expectedClass = expectedClass; - } - - public Object ReadObject() - { - return ReadObjectInternal(); - } - - public bool ReadBooleanContents() - { - return DecodeBoolean(ReadStringContentsInternal()); - } - - public bool ReadBooleanField(String fieldName, bool dflt) - { - return DecodeBoolean(ReadStringAttributeInternal(fieldName, XmlObjectEncoder.EncodeBoolean(dflt))); - } - - public byte[] ReadByteArrayContents() - { - return DecodeByteArray(ReadStringContentsInternal()); - } - - public Type ReadClassContents() - { - return DecodeClass(ReadStringContentsInternal()); - } - - public Type ReadClassField(String name, Type dflt) - { - String val = ReadStringAttributeInternal(name, null); - if (val == null) - { - return dflt; - } - else - { - return DecodeClass(val); - } - } - - public double ReadDoubleContents() - { - return DecodeDouble(ReadStringContentsInternal()); - } - - public double ReadDoubleField(String fieldName, double dflt) - { - return DecodeDouble(ReadStringAttributeInternal(fieldName, XmlObjectEncoder.EncodeDouble(dflt))); - } - - public float ReadFloatContents() - { - return DecodeFloat(ReadStringContentsInternal()); - } - - public float ReadFloatField(String fieldName, float dflt) - { - return DecodeFloat(ReadStringAttributeInternal(fieldName, XmlObjectEncoder.EncodeFloat(dflt))); - } - - public int ReadIntContents() - { - return DecodeInt(ReadStringContentsInternal()); - } - - public int ReadIntField(String fieldName, int dflt) - { - return DecodeInt(ReadStringAttributeInternal(fieldName, XmlObjectEncoder.EncodeInt(dflt))); - } - - public long ReadLongContents() - { - return DecodeLong(ReadStringContentsInternal()); - } - - public long ReadLongField(String fieldName, long dflt) - { - return DecodeLong(ReadStringAttributeInternal(fieldName, XmlObjectEncoder.EncodeLong(dflt))); - } - - public int GetNumSubObjects() - { - int count = 0; - for (XmlElement subElement = XmlUtil.GetFirstChildElement(_node); - subElement != null; - subElement = XmlUtil.GetNextElement(subElement)) - { - count++; - } - return count; - } - - public Object ReadObjectContents(int index) - { - XmlElement subElement = XmlUtil.GetFirstChildElement(_node); - for (int i = 0; i < index; i++) - { - subElement = XmlUtil.GetNextElement(subElement); - } - - if (subElement == null) - { - throw new ConnectorException("Missing subelement number: " + index); - } - - return new XmlObjectDecoder(subElement, null).ReadObject(); - } - - public Object ReadObjectField(String fieldName, Type expected, Object dflt) - { - XmlElement child = XmlUtil.FindImmediateChildElement(_node, fieldName); - if (child == null) - { - return dflt; - } - if (expected != null) - { - return new XmlObjectDecoder(child, expected).ReadObject(); - } - XmlElement subElement = XmlUtil.GetFirstChildElement(child); - if (subElement == null) - { - return dflt; - } - //if they specify null, don't apply defaults - return new XmlObjectDecoder(subElement, null).ReadObject(); - } - - public String ReadStringContents() - { - String rv = ReadStringContentsInternal(); - return rv == null ? "" : rv; - } - - public String ReadStringField(String fieldName, String dflt) - { - return ReadStringAttributeInternal(fieldName, dflt); - } - - private String ReadStringContentsInternal() - { - String xml = XmlUtil.GetContent(_node); - return xml; - } - - private String ReadStringAttributeInternal(String name, String dflt) - { - XmlAttribute attr = _node.GetAttributeNode(name); - if (attr == null) - { - return dflt; - } - return attr.Value; - } - - private bool DecodeBoolean(String v) - { - return Boolean.Parse(v); - } - - private byte[] DecodeByteArray(String base64) - { - return Convert.FromBase64String(base64); - } - - private Type DecodeClass(String type) - { - if (type.EndsWith("[]")) - { - String componentName = type.Substring(0, type.Length - "[]".Length); - Type componentClass = - DecodeClass(componentName); - Type arrayClass = - componentClass.MakeArrayType(); - return arrayClass; - } - else - { - ObjectTypeMapper mapper = - ObjectSerializerRegistry.GetMapperBySerialType(type); - if (mapper == null) - { - throw new ConnectorException("No deserializer for type: " + type); - } - Type clazz = mapper.HandledObjectType; - return clazz; - } - } - - private double DecodeDouble(String val) - { - return Double.Parse(val); - } - - private float DecodeFloat(String val) - { - return Single.Parse(val); - } - - private int DecodeInt(String val) - { - return Int32.Parse(val); - } - - private long DecodeLong(String val) - { - return Int64.Parse(val); - } - - private Object ReadObjectInternal() - { - if (_expectedClass != null) - { - ObjectSerializationHandler handler = - ObjectSerializerRegistry.GetHandlerByObjectType(_expectedClass); - if (handler == null) - { - if (_expectedClass.IsArray) - { - IList temp = new List(); - for (XmlElement child = XmlUtil.GetFirstChildElement(_node); child != null; - child = XmlUtil.GetNextElement(child)) - { - XmlObjectDecoder sub = new XmlObjectDecoder(child, null); - Object obj = sub.ReadObject(); - temp.Add(obj); - } - int length = temp.Count; - Array array = Array.CreateInstance(_expectedClass.GetElementType(), length); - for (int i = 0; i < length; i++) - { - Object element = temp[i]; - array.SetValue(element, i); - } - return array; - } - else - { - throw new ConnectorException("No deserializer for type: " + _expectedClass); - } - } - else - { - return handler.Deserialize(this); - } - } - else if (_node.LocalName.Equals("null")) - { - return null; - } - else if (_node.LocalName.Equals("Array")) - { - String componentType = XmlUtil.GetAttribute(_node, "componentType"); - if (componentType == null) - { - componentType = "Object"; - } - Type componentClass = DecodeClass(componentType); - IList temp = new List(); - for (XmlElement child = XmlUtil.GetFirstChildElement(_node); child != null; - child = XmlUtil.GetNextElement(child)) - { - XmlObjectDecoder sub = new XmlObjectDecoder(child, null); - Object obj = sub.ReadObject(); - temp.Add(obj); - } - int length = temp.Count; - Array array = Array.CreateInstance(componentClass, - length); - for (int i = 0; i < length; i++) - { - Object element = temp[i]; - array.SetValue(element, i); - } - return array; - } - else - { - Type clazz = - DecodeClass(_node.LocalName); - ObjectSerializationHandler handler = - ObjectSerializerRegistry.GetHandlerByObjectType(clazz); - if (handler == null) - { - throw new ConnectorException("No deserializer for type: " + clazz); - } - else - { - return handler.Deserialize(this); - } - } - } - } - - public class XmlObjectParser - { - public static void parse(TextReader inputSource, - XmlObjectResultsHandler handler, - bool validate) - { - XmlReaderSettings mySettings = - new XmlReaderSettings(); - if (validate) - { - mySettings.ValidationType = ValidationType.DTD; - } - mySettings.ProhibitDtd = false; - mySettings.XmlResolver = new MyEntityResolver(validate); - XmlReader reader = XmlReader.Create(inputSource, mySettings); - MyParser parser = new MyParser(handler); - parser.Parse(reader); - } - - private class MyEntityResolver : XmlResolver - { - private readonly bool _validate; - - public MyEntityResolver(bool validate) - { - _validate = validate; - } - - public override Object GetEntity(Uri absoluteUri, string role, Type ofObject) - { - String text = null; - if (absoluteUri.AbsolutePath.EndsWith(XmlObjectSerializerImpl.CONNECTORS_DTD)) - { - if (!_validate) - { - text = ""; - } - else - { - text = GetDTD(); - } - } - if (text != null) - { - byte[] bytes = Encoding.UTF8.GetBytes(text); - return new MemoryStream(bytes); - } - return null; - } - - public override ICredentials Credentials - { - set - { - - } - } - private static String GetDTD() - { - ResourceManager manager = - new ResourceManager("Org.IdentityConnectors.Resources", - typeof(XmlObjectParser).Assembly); - String contents = (String)manager.GetObject(XmlObjectSerializerImpl.CONNECTORS_DTD); - return contents; - } - } - - private class MyParser - { - /// - /// The document for the current top-level element. - /// - /// - /// with each top-level element, - /// we discard the previous to avoid accumulating memory - /// - private XmlDocument _currentTopLevelElementDocument; - - - /// - /// Stack of elements we are creating - /// - private IList _elementStack = new List(10); - - /// - /// Results handler that we write our objects to - /// - private readonly XmlObjectResultsHandler _handler; - - /// - /// Is the handler still handing - /// - private bool _stillHandling = true; - - - public MyParser(XmlObjectResultsHandler handler) - { - _handler = handler; - } - - public void Parse(XmlReader reader) - { - while (_stillHandling && reader.Read()) - { - XmlNodeType nodeType = reader.NodeType; - switch (nodeType) - { - case XmlNodeType.Element: - StartElement(reader.LocalName); - bool empty = reader.IsEmptyElement; - if (reader.MoveToFirstAttribute()) - { - AddAttribute(reader.LocalName, reader.Value); - while (reader.MoveToNextAttribute()) - { - AddAttribute(reader.LocalName, reader.Value); - } - } - if (empty) - { - EndElement(); - } - break; - case XmlNodeType.Text: - case XmlNodeType.CDATA: - case XmlNodeType.Whitespace: - case XmlNodeType.SignificantWhitespace: - AddText(reader.Value); - break; - case XmlNodeType.EndElement: - EndElement(); - break; - } - } - } - - private XmlElement GetCurrentElement() - { - if (_elementStack.Count > 0) - { - return _elementStack[_elementStack.Count - 1]; - } - else - { - return null; - } - } - - private void AddText(String text) - { - XmlElement currentElement = GetCurrentElement(); - if (currentElement != null) - { - currentElement.AppendChild(_currentTopLevelElementDocument.CreateTextNode(text)); - } - } - - private void EndElement() - { - if (_elementStack.Count > 0) //we don't push the top-level MULTI_OBJECT_ELEMENT on the stack - { - XmlElement element = _elementStack[_elementStack.Count - 1]; - _elementStack.RemoveAt(_elementStack.Count - 1); - if (_elementStack.Count == 0) - { - _currentTopLevelElementDocument = null; - if (_stillHandling) - { - XmlObjectDecoder decoder = new XmlObjectDecoder(element, null); - Object obj = decoder.ReadObject(); - _stillHandling = _handler(obj); - } - } - } - } - - - private void StartElement(String localName) - { - XmlElement element = null; - if (_elementStack.Count == 0) - { - if (!XmlObjectSerializerImpl.MULTI_OBJECT_ELEMENT.Equals(localName)) - { - _currentTopLevelElementDocument = new XmlDocument(); - element = _currentTopLevelElementDocument.CreateElement(localName); - } - } - else - { - element = - _currentTopLevelElementDocument.CreateElement(localName); - GetCurrentElement().AppendChild(element); - } - if (element != null) - { - _elementStack.Add(element); - } - } - - private void AddAttribute(String name, String val) - { - XmlElement element = GetCurrentElement(); - if (element != null) - { - element.SetAttribute(name, val); - } - } - } - } - - public class XmlObjectSerializerImpl : XmlObjectSerializer - { - - public const String MULTI_OBJECT_ELEMENT = "MultiObject"; - public const String CONNECTORS_DTD = "connectors.dtd"; - - private readonly TextWriter _output; - - private readonly bool _multiObject; - - private readonly bool _includeHeader; - - private bool _firstObjectWritten; - - private bool _documentEnded; - - public XmlObjectSerializerImpl(TextWriter output, bool includeHeader, bool multiObject) - { - _output = output; - _includeHeader = includeHeader; - _multiObject = multiObject; - } - - - /// - /// Writes the next object to the stream. - /// - /// The object to write. - /// - /// if there is more than one object - /// and this is not configured for multi-object document. - public void WriteObject(Object obj) - { - if (_documentEnded) - { - throw new InvalidOperationException("Attempt to writeObject after the document is already closed"); - } - StringBuilder buf = new StringBuilder(); - XmlObjectEncoder encoder = new XmlObjectEncoder(buf); - String elementName = encoder.WriteObject(obj); - if (!_firstObjectWritten) - { - StartDocument(elementName); - } - else - { - if (!_multiObject) - { - throw new InvalidOperationException("Attempt to write multiple objects on a single-object document"); - } - } - Write(buf.ToString()); - _firstObjectWritten = true; - } - - public void Flush() - { - _output.Flush(); - } - - public void Close(bool closeStream) - { - if (!_documentEnded) - { - if (!_firstObjectWritten) - { - if (!_multiObject) - { - throw new InvalidOperationException("Attempt to write zero objects on a single-object document"); - } - StartDocument(null); - } - WriteEndDocument(); - _documentEnded = true; - } - if (closeStream) - { - _output.Close(); - } - } - - private void StartDocument(String firstElement) - { - if (_includeHeader) - { - String docType = _multiObject ? MULTI_OBJECT_ELEMENT : firstElement; - String line1 = "\n"; - String line2 = "\n"; - Write(line1); - Write(line2); - } - if (_multiObject) - { - String line3 = "<" + MULTI_OBJECT_ELEMENT + ">\n"; - Write(line3); - } - } - - private void WriteEndDocument() - { - if (_multiObject) - { - String line1 = "\n"; - Write(line1); - } - } - - private void Write(String str) - { - _output.Write(str); - } - } -} \ No newline at end of file diff --git a/FrameworkInternal/Server.cs b/FrameworkInternal/Server.cs deleted file mode 100644 index 3316b67..0000000 --- a/FrameworkInternal/Server.cs +++ /dev/null @@ -1,1054 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Diagnostics; -using System.Globalization; -using System.Net; -using System.Net.Security; -using System.Security; -using System.Security.Cryptography.X509Certificates; -using System.Net.Sockets; -using System.IO; -using System.Linq; -using System.Threading; -using System.Reflection; -using System.Security.Authentication; -using System.Text; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Common.Security; -using Org.IdentityConnectors.Framework.Api; -using Org.IdentityConnectors.Framework.Api.Operations; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Common.Exceptions; -using Org.IdentityConnectors.Framework.Common.Objects.Filters; -using Org.IdentityConnectors.Framework.Common.Serializer; -using Org.IdentityConnectors.Framework.Server; -using Org.IdentityConnectors.Framework.Impl.Api; -using Org.IdentityConnectors.Framework.Impl.Api.Remote.Messages; -using Org.IdentityConnectors.Framework.Impl.Api.Local; -using Org.IdentityConnectors.Framework.Impl.Api.Local.Operations; -using Org.IdentityConnectors.Framework.Impl.Api.Remote; - -namespace Org.IdentityConnectors.Framework.Server -{ - /// - /// Connector server interface. - /// - public abstract class ConnectorServer - { - // At some point we might make this pluggable, but for now, hard-code - private const String IMPL_NAME - = "Org.IdentityConnectors.Framework.Impl.Server.ConnectorServerImpl"; - - /// - /// The port to listen on; - /// - private int _port = 0; - - /// - /// Base 64 sha1 hash of the connector server key - /// - /// - private String _keyHash; - - /// - /// The number of connections to queue - /// - private int _maxConnections = 300; - - /// - /// The minimum number of worker threads - /// - private int _minWorkers = 10; - - /// - /// The maximum number of worker threads - /// - private int _maxWorkers = 100; - - /// - /// The network interface address to use. - /// - private IPAddress _ifAddress = null; - - /// - /// Listen on SSL - /// - private bool _useSSL = false; - - /// - /// The server certificate to use - /// - private X509Certificate _serverCertificate = null; - - /// - /// Get the singleton instance of the . - /// - public static ConnectorServer NewInstance() - { - SafeType type = - SafeType.ForRawType(Type.GetType(IMPL_NAME, true)); - return type.CreateInstance(); - } - - private void AssertNotStarted() - { - if (IsStarted()) - { - throw new InvalidOperationException("Operation cannot be performed " + - "while server is running"); - } - } - - /// - /// Returns the port to listen on. - /// - /// The port to listen on. - public int Port - { - get - { - return _port; - } - set - { - AssertNotStarted(); - _port = value; - } - } - - /// - /// Returns the max connections to queue - /// - /// The max connections to queue - public int MaxConnections - { - get - { - return _maxConnections; - } - set - { - AssertNotStarted(); - _maxConnections = value; - } - } - - /// - /// Returns the max worker threads to allow. - /// - /// The max worker threads to allow. - public int MaxWorkers - { - get - { - return _maxWorkers; - } - set - { - AssertNotStarted(); - _maxWorkers = value; - } - } - - /// - /// Returns the min worker threads to allow. - /// - /// The min worker threads to allow. - public int MinWorkers - { - get - { - return _minWorkers; - } - set - { - AssertNotStarted(); - _minWorkers = value; - } - } - - /// - /// Returns the network interface address to bind to. - /// - /// - /// May be null. - /// - /// The network interface address to bind to or null. - public IPAddress IfAddress - { - get - { - return _ifAddress; - } - set - { - AssertNotStarted(); - _ifAddress = value; - } - } - - /// - /// Returns true iff we are to use SSL. - /// - /// true iff we are to use SSL. - public bool UseSSL - { - get - { - return _useSSL; - } - set - { - AssertNotStarted(); - _useSSL = value; - } - } - - /// - /// Returns the certificate to use for the SSL connection. - /// - public X509Certificate ServerCertificate - { - get - { - return _serverCertificate; - } - set - { - AssertNotStarted(); - _serverCertificate = value; - } - } - - public String KeyHash - { - get - { - return _keyHash; - } - set - { - AssertNotStarted(); - _keyHash = value; - } - } - - /// - /// Produces a thread dump of all pending requests - /// - abstract public void DumpRequests(); - - /// - /// Starts the server. - /// - /// - /// All server settings must be configured prior - /// to calling. The following methods are required to be called: - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - abstract public void Start(); - - /// - /// Stops the server gracefully. - /// - /// - /// Returns when all in-progress connections - /// have been serviced. - /// - abstract public void Stop(); - - /// - /// Return true iff the server is started. - /// - /// - /// Note that started is a - /// logical state (start method has been called). It does not necessarily - /// reflect the health of the server - /// - /// true iff the server is started. - abstract public bool IsStarted(); - } -} - -namespace Org.IdentityConnectors.Framework.Impl.Server -{ - public class ConnectionProcessor - { - private class RemoteResultsHandler : ObjectStreamHandler - { - private const int PAUSE_INTERVAL = 200; - - private readonly RemoteFrameworkConnection _connection; - private long _count = 0; - public RemoteResultsHandler(RemoteFrameworkConnection conn) - { - _connection = conn; - } - - public bool Handle(Object obj) - { - try - { - OperationResponsePart part = - new OperationResponsePart(null, obj); - _connection.WriteObject(part); - _count++; - if (_count % PAUSE_INTERVAL == 0) - { - _connection.WriteObject(new OperationResponsePause()); - Object message = - _connection.ReadObject(); - return message is OperationRequestMoreData; - } - else - { - return true; - } - } - catch (IOException e) - { - throw new BrokenConnectionException(e); - } - catch (Exception) - { - throw; - } - } - } - - private readonly ConnectorServerImpl _server; - private readonly RemoteFrameworkConnection _connection; - - public ConnectionProcessor(ConnectorServerImpl server, - RemoteFrameworkConnection connection) - { - _server = server; - _connection = connection; - } - - public void Run() - { - try - { - _server.BeginRequest(); - try - { - while (true) - { - bool keepGoing = ProcessRequest(); - if (!keepGoing) - { - break; - } - } - } - finally - { - try - { - _connection.Dispose(); - } - catch (Exception e) - { - TraceUtil.TraceException(null, e); - } - } - } - catch (Exception e) - { - TraceUtil.TraceException(null, e); - } - finally - { - _server.EndRequest(); - } - } - - private bool ProcessRequest() - { - CultureInfo locale; - try - { - locale = (CultureInfo)_connection.ReadObject(); - } - catch (EndOfStreamException) - { - return false; - } - - //We can't set this because C# does not like language-neutral - //cultures for CurrentCulture - this tends to blow up - //TODO: think more about this... - //Thread.CurrentThread.CurrentCulture = locale; - Thread.CurrentThread.CurrentUICulture = locale; - - GuardedString key = (GuardedString)_connection.ReadObject(); - - bool authorized; - try - { - authorized = key.VerifyBase64SHA1Hash(_server.KeyHash); - } - finally - { - key.Dispose(); - } - Org.IdentityConnectors.Framework.Common.Exceptions.InvalidCredentialException authException = null; - if (!authorized) - { - authException = new Org.IdentityConnectors.Framework.Common.Exceptions.InvalidCredentialException("Remote framework key is invalid"); - } - Object requestObject = _connection.ReadObject(); - if (requestObject is HelloRequest) - { - if (authException != null) - { - HelloResponse response = - new HelloResponse(authException, null); - _connection.WriteObject(response); - } - else - { - HelloResponse response = - ProcessHelloRequest((HelloRequest)requestObject); - _connection.WriteObject(response); - } - } - else if (requestObject is OperationRequest) - { - if (authException != null) - { - OperationResponsePart part = - new OperationResponsePart(authException, null); - _connection.WriteObject(part); - } - else - { - OperationRequest opRequest = - (OperationRequest)requestObject; - OperationResponsePart part = - ProcessOperationRequest(opRequest); - _connection.WriteObject(part); - } - } - else if (requestObject is EchoMessage) - { - if (authException != null) - { - //echo message probably doesn't need auth, but - //it couldn't hurt - actually it does for test connection - EchoMessage part = - new EchoMessage(authException, null); - _connection.WriteObject(part); - } - else - { - EchoMessage message = (EchoMessage)requestObject; - Object obj = message.Object; - String xml = message.ObjectXml; - if (xml != null) - { - Console.WriteLine("xml: \n" + xml); - Object xmlClone = - SerializerUtil.DeserializeXmlObject(xml, true); - xml = - SerializerUtil.SerializeXmlObject(xmlClone, true); - } - EchoMessage message2 = new EchoMessage(obj, xml); - _connection.WriteObject(message2); - } - } - else - { - throw new Exception("Unexpected request: " + requestObject); - } - return true; - } - - private ConnectorInfoManager GetConnectorInfoManager() - { - return ConnectorInfoManagerFactory.GetInstance().GetLocalManager(); - } - - private HelloResponse ProcessHelloRequest(HelloRequest request) - { - IList connectorInfo; - Exception exception = null; - try - { - ConnectorInfoManager manager = - GetConnectorInfoManager(); - IList localInfos = - manager.ConnectorInfos; - connectorInfo = new List(); - foreach (ConnectorInfo localInfo in localInfos) - { - LocalConnectorInfoImpl localInfoImpl = - (LocalConnectorInfoImpl)localInfo; - RemoteConnectorInfoImpl remoteInfo = - localInfoImpl.ToRemote(); - connectorInfo.Add(remoteInfo); - } - } - catch (Exception e) - { - TraceUtil.TraceException(null, e); - exception = e; - connectorInfo = null; - } - return new HelloResponse(exception, connectorInfo); - } - - private MethodInfo GetOperationMethod(OperationRequest request) - { - MethodInfo[] methods = - request.Operation.RawType.GetMethods(); - MethodInfo found = null; - foreach (MethodInfo m in methods) - { - if (m.Name.ToUpper().Equals(request.OperationMethodName.ToUpper())) - { - if (found != null) - { - throw new ConnectorException("APIOperations are expected " - + "to have exactly one method of a given name: " + request.Operation); - } - found = m; - } - } - - if (found == null) - { - throw new ConnectorException("APIOperations are expected " - + "to have exactly one method of a given name: " + request.Operation + " " + methods.Length); - } - return found; - } - - private OperationResponsePart - ProcessOperationRequest(OperationRequest request) - { - Object result; - Exception exception = null; - try - { - MethodInfo method = GetOperationMethod(request); - APIOperation operation = GetAPIOperation(request); - IList arguments = request.Arguments; - IList argumentsAndStreamHandlers = - PopulateStreamHandlers(ReflectionUtil.GetParameterTypes(method), - arguments); - try - { - Object[] args = argumentsAndStreamHandlers.ToArray(); - FixupArguments(method, args); - result = method.Invoke(operation, args); - } - catch (TargetInvocationException e) - { - Exception root = e.InnerException; - ExceptionUtil.PreserveStackTrace(root); - throw root; - } - bool anyStreams = - argumentsAndStreamHandlers.Count > arguments.Count; - if (anyStreams) - { - try - { - _connection.WriteObject(new OperationResponseEnd()); - } - catch (IOException e) - { - throw new BrokenConnectionException(e); - } - } - } - catch (BrokenConnectionException w) - { - //at this point the stream is broken - just give up - throw w.GetIOException(); - } - catch (Exception e) - { - TraceUtil.TraceException(null, e); - exception = e; - result = null; - } - return new OperationResponsePart(exception, result); - } - - private IList PopulateStreamHandlers(Type[] paramTypes, IList arguments) - { - IList rv = new List(); - bool firstStream = true; - IEnumerator argIt = arguments.GetEnumerator(); - foreach (Type paramType in paramTypes) - { - if (StreamHandlerUtil.IsAdaptableToObjectStreamHandler(paramType)) - { - if (!firstStream) - { - throw new InvalidOperationException("At most one stream handler is supported"); - } - ObjectStreamHandler osh = - new RemoteResultsHandler(_connection); - rv.Add(StreamHandlerUtil.AdaptFromObjectStreamHandler(paramType, osh)); - firstStream = false; - } - else - { - argIt.MoveNext(); - rv.Add(argIt.Current); - } - } - return rv; - } - - /// - /// When arguments are serialized, we loose the - /// generic-type of collections. We must fix - /// the arguments - /// - /// - /// - private void FixupArguments(MethodInfo method, - object[] args) - { - Type[] paramTypes = - ReflectionUtil.GetParameterTypes(method); - if (paramTypes.Length != args.Length) - { - throw new ArgumentException("Number of arguments does not match for method: " + method); - } - for (int i = 0; i < args.Length; i++) - { - args[i] = FixupArgument(paramTypes[i], - args[i]); - } - } - - private object FixupArgument(Type expectedType, - object argument) - { - //at some point, we might want this to be more general-purpose - //for now we just handle those cases that we need to - if (typeof(ICollection).Equals(expectedType)) - { - ICollection val = - (ICollection)argument; - return CollectionUtil.NewSet(val); - } - else - { - return argument; - } - } - - private APIOperation GetAPIOperation(OperationRequest request) - { - ConnectorInfoManager manager = - GetConnectorInfoManager(); - ConnectorInfo info = manager.FindConnectorInfo( - request.ConnectorKey); - if (info == null) - { - throw new Exception("No such connector: " - + request.ConnectorKey); - } - APIConfigurationImpl config = - request.Configuration; - - //re-wire the configuration with its connector info - config.ConnectorInfo = (AbstractConnectorInfo)info; - - ConnectorFacade facade = - ConnectorFacadeFactory.GetInstance().NewInstance(config); - - return facade.GetOperation(request.Operation); - } - - private class BrokenConnectionException : Exception - { - - - public BrokenConnectionException(IOException ex) - : base("", ex) - { - } - - public IOException GetIOException() - { - return (IOException)InnerException; - } - } - - } - - class ConnectionListener - { - /// - /// This is the size of our internal queue. - /// - /// - /// For now I have this - /// relatively small because I want the OS to manage the connect - /// queue coming in. That way it can properly turn away excessive - /// requests - /// - private const int INTERNAL_QUEUE_SIZE = 2; - - - /// - /// The server object that we are using - /// - private readonly ConnectorServerImpl _server; - - /// - /// The server socket. - /// - /// - /// This must be bound at the time - /// of creation. - /// - private readonly TcpListener _socket; - - /// - /// Pool of executors - /// - //TODO: add a thread pool - //private readonly ExecutorService _threadPool; - - /// - /// Set to indicated we need to start shutting down - /// - private bool _stopped = false; - - private Thread _thisThread; - - private readonly Object MUTEX = new Object(); - - /// - /// Creates the listener thread - /// - /// The server object - /// The socket (should already be bound) - public ConnectionListener(ConnectorServerImpl server, - TcpListener socket) - { - _server = server; - _socket = socket; - _thisThread = new Thread(Run) { Name = "ConnectionListener", IsBackground = false }; - //TODO: thread pool - /* _threadPool = - new ThreadPoolExecutor - (server.getMinWorkers(), - server.getMaxWorkers(), - 30, //idle time timeout - TimeUnit.SECONDS, - new ArrayBlockingQueue( - INTERNAL_QUEUE_SIZE, - true)); //fair*/ - } - - public void Start() - { - _thisThread.Start(); - } - - public void Run() - { - Trace.TraceInformation("Server started on port: " + _server.Port); - while (!IsStopped()) - { - try - { - TcpClient connection = null; - Stream stream = null; - try - { - connection = _socket.AcceptTcpClient(); - stream = connection.GetStream(); - if (_server.UseSSL) - { - SslStream sslStream = new SslStream(stream, false); - stream = sslStream; - sslStream.AuthenticateAsServer(_server.ServerCertificate, - false, - SslProtocols.Tls, - false); - } - - ConnectionProcessor processor = - new ConnectionProcessor(_server, - new RemoteFrameworkConnection(connection, stream)); - Thread thread = new Thread(processor.Run); - thread.IsBackground = false; - thread.Start(); - } - catch (Exception) - { - if (stream != null) - { - try { stream.Close(); } - catch (Exception) { } - } - if (connection != null) - { - try { connection.Close(); } - catch (Exception) { } - } - throw; - } - } - catch (Exception e) - { - //log the error unless it's because we've stopped - if (!IsStopped() || !(e is SocketException)) - { - TraceUtil.TraceException("Error processing request", e); - } - //wait a second before trying again - if (!IsStopped()) - { - Thread.Sleep(1000); - } - } - } - } - - private void MarkStopped() - { - lock (MUTEX) - { - _stopped = true; - } - } - - private bool IsStopped() - { - lock (MUTEX) - { - return _stopped; - } - } - - public void Shutdown() - { - if (Object.ReferenceEquals(Thread.CurrentThread, _thisThread)) - { - throw new ArgumentException("Shutdown may not be called from this thread"); - } - if (!IsStopped()) - { - //set the stopped flag so we no its a normal - //shutdown and don't log the SocketException - MarkStopped(); - //close the socket - this causes accept to throw an exception - _socket.Stop(); - //wait for the main listener thread to die so we don't - //get any new requests - _thisThread.Join(); - //TODO: shutdown thread pool - //wait for all in-progress requests to finish - //_threadPool.shutdown(); - } - } - } - - internal class RequestStats - { - public RequestStats() - { - } - public Thread RequestThread { get; set; } - public long StartTimeMillis { get; set; } - public long RequestID { get; set; } - } - - public class ConnectorServerImpl : ConnectorServer - { - - private readonly IDictionary - _pendingRequests = CollectionUtil.NewIdentityDictionary(); - private ConnectionListener _listener; - private Object COUNT_LOCK = new Object(); - private long _requestCount = 0; - - public override bool IsStarted() - { - return _listener != null; - } - - public void BeginRequest() - { - long requestID; - lock (COUNT_LOCK) - { - requestID = _requestCount++; - } - Thread requestThread = Thread.CurrentThread; - RequestStats stats = new RequestStats(); - stats.StartTimeMillis = - DateTimeUtil.GetCurrentUtcTimeMillis(); - stats.RequestThread = Thread.CurrentThread; - stats.RequestID = requestID; - lock (_pendingRequests) - { - _pendingRequests[stats.RequestThread] - = stats; - } - } - - public void EndRequest() - { - lock (_pendingRequests) - { - _pendingRequests.Remove(Thread.CurrentThread); - } - } - public override void DumpRequests() - { - long currentTime = DateTimeUtil.GetCurrentUtcTimeMillis(); - IDictionary - pending; - lock (_pendingRequests) - { - pending = new Dictionary(_pendingRequests); - } - StringBuilder builder = new StringBuilder(); - builder.Append("****Pending Requests Summary*****"); - foreach (RequestStats stats in pending.Values) - { - DumpStats(stats, builder, currentTime); - } - //here we purposefully use write line since - //we always want to see it. in general, don't - //use this method - Trace.WriteLine(builder.ToString()); - } - - private void DumpStats(RequestStats stats, - StringBuilder builder, - long currentTime) - { - builder.AppendLine("**Request #" + stats.RequestID + " pending for " + (currentTime - stats.StartTimeMillis) + " millis."); - StackTrace stackTrace = GetStackTrace(stats.RequestThread); - if (stackTrace == null) - { - builder.AppendLine(" "); - } - else - { - builder.AppendLine(stackTrace.ToString()); - } - } - - private static StackTrace GetStackTrace(Thread thread) - { - bool suspended = false; - try - { - thread.Suspend(); - suspended = true; - return new StackTrace(thread, true); - } - catch (ThreadStateException) - { - return null; //we missed this one - } - finally - { - if (suspended) - { - thread.Resume(); - } - } - } - - public override void Start() - { - if (IsStarted()) - { - throw new InvalidOperationException("Server is already running."); - } - if (Port == 0) - { - throw new InvalidOperationException("Port must be set prior to starting server."); - } - if (KeyHash == null) - { - throw new InvalidOperationException("Key hash must be set prior to starting server."); - } - if (UseSSL && ServerCertificate == null) - { - throw new InvalidOperationException("ServerCertificate must be set if using SSL."); - } - //make sure we are configured properly - ConnectorInfoManagerFactory.GetInstance().GetLocalManager(); - _requestCount = 0; - _pendingRequests.Clear(); - TcpListener socket = - CreateServerSocket(); - ConnectionListener listener = new ConnectionListener(this, socket); - listener.Start(); - _listener = listener; - } - - private TcpListener CreateServerSocket() - { - IPAddress addr = IfAddress; - - if (addr == null) - { - addr = IOUtil.GetIPAddress("0.0.0.0"); - } - TcpListener rv = new TcpListener(addr, Port); - //TODO: specify accept count - rv.Start(); - return rv; - } - - - public override void Stop() - { - if (_listener != null) - { - _listener.Shutdown(); - _listener = null; - } - ConnectorFacadeFactory.GetInstance().Dispose(); - } - } -} \ No newline at end of file diff --git a/FrameworkInternal/Test.cs b/FrameworkInternal/Test.cs deleted file mode 100644 index 11d6548..0000000 --- a/FrameworkInternal/Test.cs +++ /dev/null @@ -1,152 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Diagnostics; -using System.Text; - -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Framework.Api; -using Org.IdentityConnectors.Framework.Impl.Api; -using Org.IdentityConnectors.Framework.Impl.Api.Local; -using Org.IdentityConnectors.Framework.Impl.Api.Local.Operations; -using Org.IdentityConnectors.Framework.Common; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Common.Objects.Filters; -using Org.IdentityConnectors.Framework.Spi; -using Org.IdentityConnectors.Framework.Spi.Operations; -using Org.IdentityConnectors.Test.Common.Spi; - -namespace Org.IdentityConnectors.Framework.Impl.Test -{ - public class TestHelpersImpl : TestHelpersSpi - { - /// - /// Method for convenient testing of local connectors. - /// - public APIConfiguration CreateTestConfiguration(SafeType clazz, - Configuration config) - { - LocalConnectorInfoImpl info = new LocalConnectorInfoImpl(); - info.ConnectorConfigurationClass = SafeType.Get(config); - info.ConnectorClass = (clazz); - info.ConnectorDisplayNameKey = ("DUMMY_DISPLAY_NAME"); - info.ConnectorKey = ( - new ConnectorKey(clazz.RawType.Name + ".bundle", - "1.0", - clazz.RawType.Name)); - info.Messages = (this.CreateDummyMessages()); - APIConfigurationImpl rv = new APIConfigurationImpl(); - rv.IsConnectorPoolingSupported = ( - IsConnectorPoolingSupported(clazz)); - ConfigurationPropertiesImpl properties = - CSharpClassProperties.CreateConfigurationProperties(config); - rv.ConfigurationProperties = (properties); - rv.ConnectorInfo = (info); - rv.SupportedOperations = ( - FrameworkUtil.GetDefaultSupportedOperations(clazz)); - info.DefaultAPIConfiguration = ( - rv); - return rv; - } - - public void FillConfiguration(Configuration config, IDictionary configData) - { - IDictionary configDataCopy = new Dictionary(configData); - ConfigurationPropertiesImpl configProps = - CSharpClassProperties.CreateConfigurationProperties(config); - foreach (string propName in configProps.PropertyNames) - { - object value; - if (configDataCopy.TryGetValue(propName, out value)) - { - // Remove the entry from the config map, so that at the end - // the map only contains entries that were not assigned to a config property. - configDataCopy.Remove(propName); - configProps.SetPropertyValue(propName, value); - } - } - // The config map now contains entries that were not assigned to a config property. - foreach (string propName in configDataCopy.Keys) - { - Trace.TraceWarning("Configuration property {0} does not exist!", propName); - } - CSharpClassProperties.MergeIntoBean(configProps, config); - } - - private static bool IsConnectorPoolingSupported(SafeType clazz) - { - return ReflectionUtil.IsParentTypeOf(typeof(PoolableConnector), clazz.RawType); - } - - /// - /// Performs a raw, unfiltered search at the SPI level, - /// eliminating duplicates from the result set. - /// - /// The search SPI - /// The object class - passed through to - /// connector so it may be null if the connecor - /// allowing it to be null. (This is convenient for - /// unit tests, but will not be the case in general) - /// The filter to search on - /// The result handler - /// The options - may be null - will - /// be cast to an empty OperationOptions - public void Search(SearchOp search, - ObjectClass oclass, - Filter filter, - ResultsHandler handler, - OperationOptions options) where T : class - { - if (options == null) - { - options = new OperationOptionsBuilder().Build(); - } - RawSearcherImpl.RawSearch( - search, oclass, filter, handler, options); - } - - public ConnectorMessages CreateDummyMessages() - { - return new DummyConnectorMessages(); - } - - private class DummyConnectorMessages : ConnectorMessages - { - public String Format(String key, String dflt, params Object[] args) - { - StringBuilder builder = new StringBuilder(); - builder.Append(key); - builder.Append(": "); - String sep = ""; - foreach (Object arg in args) - { - builder.Append(sep); - builder.Append(arg); - sep = ", "; - } - return builder.ToString(); - } - } - } -} \ No newline at end of file diff --git a/FrameworkInternal/version.template b/FrameworkInternal/version.template deleted file mode 100644 index db70057..0000000 --- a/FrameworkInternal/version.template +++ /dev/null @@ -1 +0,0 @@ -1.2.0.0 diff --git a/FrameworkTests/CollectionUtilTests.cs b/FrameworkTests/CollectionUtilTests.cs deleted file mode 100644 index 9f4c74a..0000000 --- a/FrameworkTests/CollectionUtilTests.cs +++ /dev/null @@ -1,162 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 NUnit.Framework; -using NUnit.Framework.SyntaxHelpers; -using Org.IdentityConnectors.Common; -namespace FrameworkTests -{ - [TestFixture] - public class CollectionUtilTests - { - [Test] - public void TestEquals() - { - Assert.IsTrue(CollectionUtil.Equals(null, null)); - Assert.IsFalse(CollectionUtil.Equals(null, "str")); - Assert.IsTrue(CollectionUtil.Equals("str", "str")); - - byte[] arr1 = new byte[] { 1, 2, 3 }; - byte[] arr2 = new byte[] { 1, 2, 3 }; - byte[] arr3 = new byte[] { 1, 2, 4 }; - byte[] arr4 = new byte[] { 1, 2 }; - int[] arr5 = new int[] { 1, 2, 3 }; - - Assert.IsTrue(CollectionUtil.Equals(arr1, arr2)); - Assert.IsFalse(CollectionUtil.Equals(arr2, arr3)); - Assert.IsFalse(CollectionUtil.Equals(arr2, arr4)); - Assert.IsFalse(CollectionUtil.Equals(arr2, arr5)); - - IList list1 = new List(); - IList list2 = new List(); - list1.Add(arr1); - list2.Add(arr2); - - Assert.IsTrue(CollectionUtil.Equals(list1, list2)); - - list2.Add(arr2); - Assert.IsFalse(CollectionUtil.Equals(list1, list2)); - - list1.Add(arr1); - Assert.IsTrue(CollectionUtil.Equals(list1, list2)); - - list1.Add(arr1); - list2.Add(arr3); - Assert.IsFalse(CollectionUtil.Equals(list1, list2)); - - IDictionary map1 = new Dictionary(); - IDictionary map2 = new Dictionary(); - map1["key1"] = arr1; - map2["key1"] = arr2; - Assert.IsTrue(CollectionUtil.Equals(map1, map2)); - map2["key2"] = arr2; - Assert.IsFalse(CollectionUtil.Equals(map1, map2)); - map1["key2"] = arr1; - Assert.IsTrue(CollectionUtil.Equals(map1, map2)); - map1["key2"] = arr3; - Assert.IsFalse(CollectionUtil.Equals(map1, map2)); - - ICollection set1 = new HashSet(); - ICollection set2 = new HashSet(); - set1.Add("val"); - set2.Add("val"); - Assert.IsTrue(CollectionUtil.Equals(set1, set2)); - set2.Add("val2"); - Assert.IsFalse(CollectionUtil.Equals(set1, set2)); - set1.Add("val2"); - Assert.IsTrue(CollectionUtil.Equals(set1, set2)); - } - [Test] - public void TestHashCode() - { - Assert.AreEqual(0, CollectionUtil.GetHashCode(null)); - Assert.AreEqual("str".GetHashCode(), CollectionUtil.GetHashCode("str")); - - byte[] arr1 = new byte[] { 1, 2, 3 }; - byte[] arr2 = new byte[] { 1, 2, 3 }; - byte[] arr3 = new byte[] { 1, 2, 4 }; - byte[] arr4 = new byte[] { 1, 2 }; - int[] arr5 = new int[] { 1, 2, 3 }; - - Assert.AreEqual(CollectionUtil.GetHashCode(arr1), - CollectionUtil.GetHashCode(arr2)); - Assert.IsFalse(CollectionUtil.GetHashCode(arr2) == - CollectionUtil.GetHashCode(arr3)); - Assert.IsFalse(CollectionUtil.GetHashCode(arr2) == - CollectionUtil.GetHashCode(arr4)); - Assert.IsTrue(CollectionUtil.GetHashCode(arr2) == - CollectionUtil.GetHashCode(arr5)); - - List list1 = new List(); - List list2 = new List(); - list1.Add(arr1); - list2.Add(arr2); - - Assert.IsTrue(CollectionUtil.GetHashCode(list1) == - CollectionUtil.GetHashCode(list2)); - - list2.Add(arr2); - Assert.IsFalse(CollectionUtil.GetHashCode(list1) == - CollectionUtil.GetHashCode(list2)); - - list1.Add(arr1); - Assert.IsTrue(CollectionUtil.GetHashCode(list1) == - CollectionUtil.GetHashCode(list2)); - - list1.Add(arr1); - list2.Add(arr3); - Assert.IsFalse(CollectionUtil.GetHashCode(list1) == - CollectionUtil.GetHashCode(list2)); - - Dictionary map1 = new Dictionary(); - Dictionary map2 = new Dictionary(); - map1["key1"] = arr1; - map2["key1"] = arr2; - Assert.IsTrue(CollectionUtil.GetHashCode(map1) == - CollectionUtil.GetHashCode(map2)); - map2["key2"] = arr2; - Assert.IsFalse(CollectionUtil.GetHashCode(map1) == - CollectionUtil.GetHashCode(map2)); - map1["key2"] = arr1; - Assert.IsTrue(CollectionUtil.GetHashCode(map1) == - CollectionUtil.GetHashCode(map2)); - map1["key2"] = arr3; - Assert.IsFalse(CollectionUtil.GetHashCode(map1) == - CollectionUtil.GetHashCode(map2)); - - HashSet set1 = new HashSet(); - HashSet set2 = new HashSet(); - set1.Add("val"); - set2.Add("val"); - Assert.IsTrue(CollectionUtil.GetHashCode(set1) == - CollectionUtil.GetHashCode(set2)); - set2.Add("val2"); - Assert.IsFalse(CollectionUtil.GetHashCode(set1) == - CollectionUtil.GetHashCode(set2)); - set1.Add("val2"); - Assert.IsTrue(CollectionUtil.GetHashCode(set1) == - CollectionUtil.GetHashCode(set2)); - } - } -} \ No newline at end of file diff --git a/FrameworkTests/ConnectorAttributeUtilTests.cs b/FrameworkTests/ConnectorAttributeUtilTests.cs deleted file mode 100644 index bc971b3..0000000 --- a/FrameworkTests/ConnectorAttributeUtilTests.cs +++ /dev/null @@ -1,62 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 NUnit.Framework; -using Org.IdentityConnectors.Framework.Common.Objects; - -namespace FrameworkTests -{ - [TestFixture] - public class ConnectorAttributeUtilTests - { - - [Test] - public void TestNamesEqual() - { - Assert.IsTrue(ConnectorAttributeUtil.NamesEqual("givenName", "givenname")); - } - - [Test] - [ExpectedException(typeof(ArgumentException))] - public void TestGetSingleValue() - { - object TEST_VALUE = 1L; - ConnectorAttribute attr = ConnectorAttributeBuilder.Build("long", TEST_VALUE); - object value = ConnectorAttributeUtil.GetSingleValue(attr); - Assert.AreEqual(TEST_VALUE, value); - - // test null - attr = ConnectorAttributeBuilder.Build("long"); - value = ConnectorAttributeUtil.GetSingleValue(attr); - Assert.IsNull(value); - // test empty - attr = ConnectorAttributeBuilder.Build("long", new List()); - value = ConnectorAttributeUtil.GetSingleValue(attr); - Assert.IsNull(value); - // test illegal argument exception - ConnectorAttributeUtil.GetSingleValue(ConnectorAttributeBuilder.Build("bob", 1, 2, 3)); - } - } -} diff --git a/FrameworkTests/ConnectorFacadeExceptionTests.cs b/FrameworkTests/ConnectorFacadeExceptionTests.cs deleted file mode 100644 index a2eef98..0000000 --- a/FrameworkTests/ConnectorFacadeExceptionTests.cs +++ /dev/null @@ -1,124 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Linq; -using System.Text; -using NUnit.Framework; -using System.Diagnostics; -using Org.IdentityConnectors.Framework.Api; -using Org.IdentityConnectors.Framework.Spi; -using Org.IdentityConnectors.Framework.Spi.Operations; -using Org.IdentityConnectors.Test.Common; -using Org.IdentityConnectors.Common; - -namespace FrameworkTests -{ - [TestFixture] - public class ConnectorFacadeExceptionTests - { - /// - /// The test specific exception that is intended to be distinguished from the exceptions the framework - /// might throw. - /// - private class EUTestException : Exception - { - } - - private class SpyConnector : Connector, TestOp - { - #region Member variables - private static StackTrace _stackTrace; - #endregion - - #region Properties - /// - /// Gets the stack trace of the last call to the method performed on - /// any instance of this class. - /// - public static StackTrace StackTrace - { - get - { - return _stackTrace; - } - } - #endregion - - #region Connector Members - public void Init(Configuration configuration) - { - } - #endregion - - #region IDisposable Members - public void Dispose() - { - } - #endregion - - #region TestOp Members - public void Test() - { - //do not insert file info, as the stack trace of the exception and the dumped stack trace - //will always differ in the line numbers - _stackTrace = new StackTrace(false); - throw new EUTestException(); - } - #endregion - } - - private class MockConfiguration : AbstractConfiguration - { - public override void Validate() - { - } - } - - /// - /// Tests whether the implementation let the exception - thrown by a connector - - /// propagate to the caller with the call stack representation from the method that throws the exception. - /// - /// The current implementation uses reflection that can hide the original - /// exception. See for more information. - [Test] - public void TestStackTraceOfExceptionThrownByConnectorFacade() - { - ConnectorFacadeFactory factory = ConnectorFacadeFactory.GetInstance(); - Configuration config = new MockConfiguration(); - ConnectorFacade facade = factory.NewInstance( - TestHelpers.CreateTestConfiguration(SafeType.Get(), config)); - - try - { - facade.Test(); - - Assert.Fail("Exception was not thrown"); - } - catch (EUTestException eutex) - { - ExceptionUtilTestHelpers.AssertStackTrace(eutex, SpyConnector.StackTrace); - } - } - } -} diff --git a/FrameworkTests/ConnectorFacadeTests.cs b/FrameworkTests/ConnectorFacadeTests.cs deleted file mode 100755 index 68a50ea..0000000 --- a/FrameworkTests/ConnectorFacadeTests.cs +++ /dev/null @@ -1,415 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 NUnit.Framework; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Common.Security; -using Org.IdentityConnectors.Framework.Api; -using Org.IdentityConnectors.Framework.Api.Operations; -using Org.IdentityConnectors.Framework.Common; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Spi; -using Org.IdentityConnectors.Framework.Spi.Operations; -using Org.IdentityConnectors.Test.Common; - -namespace FrameworkTests -{ - - [TestFixture] - public class ConnectorFacadeTests - { - - [SetUp] - public void setup() - { - // always reset the call patterns.. - MockConnector.Reset(); - } - - private class TestOperationPattern - { - /// - /// Simple call back to make the 'facade' calls. - /// - public Action MakeCall; - - /// - /// Given the list of calls determine if they match expected values based - /// on the calls made in the method. - /// - public Action> CheckCalls; - } - - /// - /// Test the pattern of the common operations. - /// - private void TestCallPattern(TestOperationPattern pattern) - { - TestCallPattern(pattern, SafeType.Get()); - } - - private void TestCallPattern(TestOperationPattern pattern, - SafeType clazz) - { - Configuration config = new MockConfiguration(false); - ConnectorFacadeFactory factory = ConnectorFacadeFactory.GetInstance(); - // **test only** - APIConfiguration impl = TestHelpers.CreateTestConfiguration(clazz, config); - ConnectorFacade facade; - facade = factory.NewInstance(impl); - // make the call on the connector facade.. - pattern.MakeCall(facade); - // check the call structure.. - IList calls = MockConnector.GetCallPattern(); - // check the call pattern.. - Assert.AreEqual("Init", calls[0].MethodName); - calls.RemoveAt(0); - pattern.CheckCalls(calls); - Assert.AreEqual("Dispose", calls[0].MethodName); - calls.RemoveAt(0); - Assert.IsTrue(calls.Count == 0); - } - - /// - /// Tests that if an SPI operation is not implemented that the API will throw - /// an . - /// - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void UnsupportedOperationTest() - { - Configuration config = new MockConfiguration(false); - SafeType clazz = SafeType.Get(); - ConnectorFacadeFactory factory = ConnectorFacadeFactory.GetInstance(); - APIConfiguration impl = TestHelpers.CreateTestConfiguration(clazz, - config); - ConnectorFacade facade; - facade = factory.NewInstance(impl); - facade.Authenticate(ObjectClass.ACCOUNT, "fadf", new GuardedString(), null); - } - - [Test] - public void RunScriptOnConnectorCallPattern() - { - TestCallPattern(new TestOperationPattern() - { - MakeCall = facade => - { - facade.RunScriptOnConnector( - new ScriptContextBuilder("lang", "script").Build(), - null); - }, - CheckCalls = calls => - { - Assert.AreEqual("RunScriptOnConnector", GetAndRemoveMethodName(calls)); - } - }); - } - - [Test] - public void RunScriptOnResourceCallPattern() - { - TestCallPattern(new TestOperationPattern() - { - MakeCall = facade => - { - facade.RunScriptOnResource( - new ScriptContextBuilder("lang", "script").Build(), - null); - }, - CheckCalls = calls => - { - Assert.AreEqual("RunScriptOnResource", GetAndRemoveMethodName(calls)); - } - }); - } - - /// - /// Test the call pattern to get the schema. - /// - [Test] - public void SchemaCallPattern() - { - TestCallPattern(new TestOperationPattern() - { - MakeCall = facade => - { - facade.Schema(); - }, - CheckCalls = calls => - { - Assert.AreEqual("Schema", GetAndRemoveMethodName(calls)); - } - }); - } - - [Test] - public void AuthenticateCallPattern() - { - TestCallPattern(new TestOperationPattern() - { - MakeCall = facade => - { - facade.Authenticate(ObjectClass.ACCOUNT, "dfadf", new GuardedString(), null); - }, - CheckCalls = calls => - { - Assert.AreEqual("Authenticate", GetAndRemoveMethodName(calls)); - } - }); - } - - [Test] - public void ResolveUsernameCallPattern() - { - TestCallPattern(new TestOperationPattern() - { - MakeCall = facade => - { - facade.ResolveUsername(ObjectClass.ACCOUNT, "dfadf", null); - }, - CheckCalls = calls => - { - Assert.AreEqual("ResolveUsername", GetAndRemoveMethodName(calls)); - } - }); - } - - [Test] - public void CreateCallPattern() - { - TestCallPattern(new TestOperationPattern() - { - MakeCall = facade => - { - ICollection attrs = CollectionUtil.NewReadOnlySet(); - facade.Create(ObjectClass.ACCOUNT, attrs, null); - }, - CheckCalls = calls => - { - Assert.AreEqual("Create", GetAndRemoveMethodName(calls)); - } - }); - } - - [Test] - [ExpectedException(typeof(ArgumentNullException))] - public void CreateWithOutObjectClassPattern() - { - TestCallPattern(new TestOperationPattern() - { - MakeCall = facade => - { - ICollection attrs = new HashSet(); - facade.Create(null, attrs, null); - }, - CheckCalls = calls => - { - Assert.Fail("Should not get here.."); - } - }); - } - - [Test] - [ExpectedException(typeof(ArgumentException))] - public void createDuplicatConnectorAttributesPattern() - { - TestCallPattern(new TestOperationPattern() - { - MakeCall = facade => - { - ICollection attrs = new HashSet(); - attrs.Add(ConnectorAttributeBuilder.Build("abc", 1)); - attrs.Add(ConnectorAttributeBuilder.Build("abc", 2)); - facade.Create(ObjectClass.ACCOUNT, attrs, null); - }, - CheckCalls = calls => - { - Assert.Fail("Should not get here.."); - } - }); - } - - [Test] - public void UpdateCallPattern() - { - TestCallPattern(new TestOperationPattern() - { - MakeCall = facade => - { - ICollection attrs = new HashSet(); - attrs.Add(ConnectorAttributeBuilder.Build("accountid")); - facade.Update(ObjectClass.ACCOUNT, NewUid(0), attrs, null); - }, - CheckCalls = calls => - { - Assert.AreEqual("Update", GetAndRemoveMethodName(calls)); - } - }); - } - - [Test] - public void DeleteCallPattern() - { - TestCallPattern(new TestOperationPattern() - { - MakeCall = facade => - { - facade.Delete(ObjectClass.ACCOUNT, NewUid(0), null); - }, - CheckCalls = calls => - { - Assert.AreEqual("Delete", GetAndRemoveMethodName(calls)); - } - }); - } - - [Test] - public void SearchCallPattern() - { - TestCallPattern(new TestOperationPattern() - { - MakeCall = facade => - { - // create an empty results handler.. - ResultsHandler rh = obj => - { - return true; - }; - // call the search method.. - facade.Search(ObjectClass.ACCOUNT, null, rh, null); - }, - CheckCalls = calls => - { - Assert.AreEqual("CreateFilterTranslator", GetAndRemoveMethodName(calls)); - Assert.AreEqual("ExecuteQuery", GetAndRemoveMethodName(calls)); - } - }); - } - - [Test] - public void GetCallPattern() - { - TestCallPattern(new TestOperationPattern() - { - MakeCall = facade => - { - // create an empty results handler.. - // call the search method.. - facade.GetObject(ObjectClass.ACCOUNT, NewUid(0), null); - }, - CheckCalls = calls => - { - Assert.AreEqual("CreateFilterTranslator", GetAndRemoveMethodName(calls)); - Assert.AreEqual("ExecuteQuery", GetAndRemoveMethodName(calls)); - } - }); - } - - [Test] - public void TestOpCallPattern() - { - TestCallPattern(new TestOperationPattern() - { - MakeCall = facade => - { - facade.Test(); - }, - CheckCalls = calls => - { - Assert.AreEqual("Test", GetAndRemoveMethodName(calls)); - } - }); - } - - [Test] - public void UpdateMergeTests() - { - ConnectorAttribute expected, actual; - Configuration config = new MockConfiguration(false); - ConnectorFacadeFactory factory = ConnectorFacadeFactory.GetInstance(); - SafeType clazz = SafeType.Get(); - // **test only** - APIConfiguration impl = TestHelpers.CreateTestConfiguration(clazz, config); - impl.SetTimeout(SafeType.Get(), APIConstants.NO_TIMEOUT); - impl.SetTimeout(SafeType.Get(), APIConstants.NO_TIMEOUT); - impl.SetTimeout(SafeType.Get(), APIConstants.NO_TIMEOUT); - ConnectorFacade facade = factory.NewInstance(impl); - // sniff test to make sure we can get an object.. - ConnectorObject obj = facade.GetObject(ObjectClass.ACCOUNT, NewUid(1), null); - Assert.AreEqual(NewUid(1), obj.Uid); - // ok lets add an attribute that doesn't exist.. - String ADDED = "somthing to add to the object"; - String ATTR_NAME = "added"; - ICollection addAttrSet; - addAttrSet = CollectionUtil.NewSet((IEnumerable)obj.GetAttributes()); - addAttrSet.Add(ConnectorAttributeBuilder.Build(ATTR_NAME, ADDED)); - Name name = obj.Name; - addAttrSet.Remove(name); - Uid uid = facade.AddAttributeValues(ObjectClass.ACCOUNT, obj.Uid, ConnectorAttributeUtil.FilterUid(addAttrSet), null); - // get back the object and see if there are the same.. - addAttrSet.Add(name); - ConnectorObject addO = new ConnectorObject(ObjectClass.ACCOUNT, addAttrSet); - obj = facade.GetObject(ObjectClass.ACCOUNT, NewUid(1), null); - Assert.AreEqual(addO, obj); - // attempt to add on to an existing attribute.. - addAttrSet.Remove(name); - uid = facade.AddAttributeValues(ObjectClass.ACCOUNT, obj.Uid, ConnectorAttributeUtil.FilterUid(addAttrSet), null); - // get the object back out and check on it.. - obj = facade.GetObject(ObjectClass.ACCOUNT, uid, null); - expected = ConnectorAttributeBuilder.Build(ATTR_NAME, ADDED, ADDED); - actual = obj.GetAttributeByName(ATTR_NAME); - Assert.AreEqual(expected, actual); - // attempt to delete a value from an attribute.. - ICollection deleteAttrs = CollectionUtil.NewSet((IEnumerable)addO.GetAttributes()); - deleteAttrs.Remove(name); - uid = facade.RemoveAttributeValues(ObjectClass.ACCOUNT, addO.Uid, ConnectorAttributeUtil.FilterUid(deleteAttrs), null); - obj = facade.GetObject(ObjectClass.ACCOUNT, uid, null); - expected = ConnectorAttributeBuilder.Build(ATTR_NAME, ADDED); - actual = obj.GetAttributeByName(ATTR_NAME); - Assert.AreEqual(expected, actual); - // attempt to delete an attribute that doesn't exist.. - ICollection nonExist = new HashSet(); - nonExist.Add(NewUid(1)); - nonExist.Add(ConnectorAttributeBuilder.Build("does not exist", "asdfe")); - uid = facade.RemoveAttributeValues(ObjectClass.ACCOUNT, addO.Uid, ConnectorAttributeUtil.FilterUid(nonExist), null); - obj = facade.GetObject(ObjectClass.ACCOUNT, NewUid(1), null); - Assert.IsTrue(obj.GetAttributeByName("does not exist") == null); - } - - static Uid NewUid(int id) - { - return new Uid(Convert.ToString(id)); - } - - static string GetAndRemoveMethodName(IList calls) - { - string result = calls[0].MethodName; - calls.RemoveAt(0); - return result; - } - } -} \ No newline at end of file diff --git a/FrameworkTests/ConnectorInfoManagerTests.cs b/FrameworkTests/ConnectorInfoManagerTests.cs deleted file mode 100644 index 1e97ed4..0000000 --- a/FrameworkTests/ConnectorInfoManagerTests.cs +++ /dev/null @@ -1,623 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 NUnit.Framework; -using NUnit.Framework.SyntaxHelpers; -using System.Collections.Generic; -using System.Diagnostics; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Common.Security; -using Org.IdentityConnectors.Framework.Api; -using Org.IdentityConnectors.Framework.Api.Operations; -using Org.IdentityConnectors.Framework.Common.Exceptions; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Server; -using Org.IdentityConnectors.Framework.Impl.Api; -using Org.IdentityConnectors.Framework.Impl.Api.Local; -using System.Security; -using System.Threading; -using System.Globalization; -using System.Net; -using System.Net.Security; -using System.Security.Cryptography.X509Certificates; -namespace FrameworkTests -{ - [TestFixture] - public class ConnectorInfoManagerTests - { - private static ConnectorInfo FindConnectorInfo - (ConnectorInfoManager manager, - string version, - string connectorName) - { - foreach (ConnectorInfo info in manager.ConnectorInfos) - { - ConnectorKey key = info.ConnectorKey; - if (version.Equals(key.BundleVersion) && - connectorName.Equals(key.ConnectorName)) - { - //intentionally ineffecient to test - //more code - return manager.FindConnectorInfo(key); - } - } - return null; - } - - [TearDown] - public void TearDown() - { - ShutdownConnnectorInfoManager(); - } - - [Test] - public void TestClassLoading() - { - ConnectorInfoManager manager = - GetConnectorInfoManager(); - ConnectorInfo info1 = - FindConnectorInfo(manager, - "1.0.0.0", - "org.identityconnectors.testconnector.TstConnector"); - Assert.IsNotNull(info1); - ConnectorInfo info2 = - FindConnectorInfo(manager, - "2.0.0.0", - "org.identityconnectors.testconnector.TstConnector"); - - Assert.IsNotNull(info2); - - ConnectorFacade facade1 = - ConnectorFacadeFactory.GetInstance().NewInstance(info1.CreateDefaultAPIConfiguration()); - - ConnectorFacade facade2 = - ConnectorFacadeFactory.GetInstance().NewInstance(info2.CreateDefaultAPIConfiguration()); - - ICollection attrs = new HashSet(); - Assert.AreEqual("1.0", facade1.Create(ObjectClass.ACCOUNT, attrs, null).GetUidValue()); - Assert.AreEqual("2.0", facade2.Create(ObjectClass.ACCOUNT, attrs, null).GetUidValue()); - } - - [Test] - public void TestAPIConfiguration() - { - ConnectorInfoManager manager = - GetConnectorInfoManager(); - ConnectorInfo info = - FindConnectorInfo(manager, - "1.0.0.0", - "org.identityconnectors.testconnector.TstConnector"); - Assert.IsNotNull(info); - APIConfiguration api = info.CreateDefaultAPIConfiguration(); - - ConfigurationProperties props = api.ConfigurationProperties; - ConfigurationProperty property = props.GetProperty("tstField"); - - Assert.IsNotNull(property); - ICollection> operations = - property.Operations; - Assert.AreEqual(1, operations.Count); - Assert.IsTrue(operations.Contains(SafeType.Get())); - - Thread.CurrentThread.CurrentUICulture = new CultureInfo("en"); - Assert.AreEqual("Help for test field.", property.GetHelpMessage(null)); - Assert.AreEqual("Display for test field.", property.GetDisplayName(null)); - Assert.AreEqual("Test Framework Value", - info.Messages.Format("TEST_FRAMEWORK_KEY", "empty")); - - CultureInfo eslocale = new CultureInfo("es"); - Thread.CurrentThread.CurrentUICulture = eslocale; - Assert.AreEqual("tstField.help_es", property.GetHelpMessage(null)); - Assert.AreEqual("tstField.display_es", property.GetDisplayName(null)); - - CultureInfo esESlocale = new CultureInfo("es-ES"); - Thread.CurrentThread.CurrentUICulture = esESlocale; - Assert.AreEqual("tstField.help_es-ES", property.GetHelpMessage(null)); - Assert.AreEqual("tstField.display_es-ES", property.GetDisplayName(null)); - - CultureInfo esARlocale = new CultureInfo("es-AR"); - Thread.CurrentThread.CurrentUICulture = esARlocale; - Assert.AreEqual("tstField.help_es", property.GetHelpMessage(null)); - Assert.AreEqual("tstField.display_es", property.GetDisplayName(null)); - - ConnectorFacadeFactory facf = ConnectorFacadeFactory.GetInstance(); - ConnectorFacade facade = facf.NewInstance(api); - // call the various create/update/delete commands.. - facade.Schema(); - } - - [Test] - public void TestValidate() - { - ConnectorInfoManager manager = - GetConnectorInfoManager(); - ConnectorInfo info = - FindConnectorInfo(manager, - "1.0.0.0", - "org.identityconnectors.testconnector.TstConnector"); - - APIConfiguration api = info.CreateDefaultAPIConfiguration(); - - ConfigurationProperties props = api.ConfigurationProperties; - ConfigurationProperty property = props.GetProperty("failValidation"); - property.Value = false; - ConnectorFacadeFactory facf = ConnectorFacadeFactory.GetInstance(); - ConnectorFacade facade = facf.NewInstance(api); - facade.Validate(); - property.Value = true; - facade = facf.NewInstance(api); - try - { - Thread.CurrentThread.CurrentUICulture = new CultureInfo("en"); - facade.Validate(); - Assert.Fail("exception expected"); - } - catch (ConnectorException e) - { - Assert.AreEqual("validation failed en", e.Message); - } - try - { - Thread.CurrentThread.CurrentUICulture = new CultureInfo("es"); - facade.Validate(); - Assert.Fail("exception expected"); - } - catch (ConnectorException e) - { - Assert.AreEqual("validation failed es", e.Message); - } - } - - /// - /// Main purpose of this is to test searching with - /// many results and that we can properly handle - /// stopping in the middle of this. - /// - /// - /// There's a bunch of - /// code in the remote stuff that is there to handle this - /// in particular that we want to excercise. - /// - [Test] - public void TestSearchWithManyResults() - { - ConnectorInfoManager manager = - GetConnectorInfoManager(); - ConnectorInfo info = - FindConnectorInfo(manager, - "1.0.0.0", - "org.identityconnectors.testconnector.TstConnector"); - - APIConfiguration api = info.CreateDefaultAPIConfiguration(); - - ConfigurationProperties props = api.ConfigurationProperties; - ConfigurationProperty property = props.GetProperty("numResults"); - - //1000 is several times the remote size between pauses - property.Value = 1000; - - ConnectorFacadeFactory facf = ConnectorFacadeFactory.GetInstance(); - ConnectorFacade facade = facf.NewInstance(api); - - IList results = new List(); - - facade.Search(ObjectClass.ACCOUNT, null, - obj => - { - results.Add(obj); - return true; - }, null); - - Assert.AreEqual(1000, results.Count); - for (int i = 0; i < results.Count; i++) - { - ConnectorObject obj = results[i]; - Assert.AreEqual(i.ToString(), - obj.Uid.GetUidValue()); - } - - results.Clear(); - - facade.Search(ObjectClass.ACCOUNT, null, - obj => - { - if (results.Count < 500) - { - results.Add(obj); - return true; - } - else - { - return false; - } - }, null); - - Assert.AreEqual(500, results.Count); - for (int i = 0; i < results.Count; i++) - { - ConnectorObject obj = results[i]; - Assert.AreEqual(i.ToString(), - obj.Uid.GetUidValue()); - } - } - /// - /// Main purpose of this is to test sync with - /// many results and that we can properly handle - /// stopping in the middle of this. - /// - /// - /// There's a bunch of - /// code in the remote stuff that is there to handle this - /// in particular that we want to excercise. - /// - [Test] - public void TestSyncWithManyResults() - { - ConnectorInfoManager manager = - GetConnectorInfoManager(); - ConnectorInfo info = - FindConnectorInfo(manager, - "1.0.0.0", - "org.identityconnectors.testconnector.TstConnector"); - - APIConfiguration api = info.CreateDefaultAPIConfiguration(); - - ConfigurationProperties props = api.ConfigurationProperties; - ConfigurationProperty property = props.GetProperty("numResults"); - - //1000 is several times the remote size between pauses - property.Value = (1000); - - ConnectorFacadeFactory facf = ConnectorFacadeFactory.GetInstance(); - ConnectorFacade facade = facf.NewInstance(api); - - SyncToken latest = facade.GetLatestSyncToken(ObjectClass.ACCOUNT); - Assert.AreEqual("mylatest", latest.Value); - IList results = new List(); - - facade.Sync(ObjectClass.ACCOUNT, null, obj => - { - results.Add(obj); - return true; - }, null); - - Assert.AreEqual(1000, results.Count); - for (int i = 0; i < results.Count; i++) - { - SyncDelta obj = results[i]; - Assert.AreEqual(i.ToString(), - obj.Uid.GetUidValue()); - } - - results.Clear(); - - facade.Sync(ObjectClass.ACCOUNT, - null, - obj => - { - if (results.Count < 500) - { - results.Add(obj); - return true; - } - else - { - return false; - } - }, null); - - Assert.AreEqual(500, results.Count); - for (int i = 0; i < results.Count; i++) - { - SyncDelta obj = results[i]; - Assert.AreEqual(i.ToString(), - obj.Uid.GetUidValue()); - } - } - - [Test] - public void TestConnectionPooling() - { - ConnectorPoolManager.Dispose(); - ConnectorInfoManager manager = - GetConnectorInfoManager(); - ConnectorInfo info1 = - FindConnectorInfo(manager, - "1.0.0.0", - "org.identityconnectors.testconnector.TstConnector"); - Assert.IsNotNull(info1); - //reset connection count - { - //trigger TstConnection.init to be called - APIConfiguration config2 = - info1.CreateDefaultAPIConfiguration(); - config2.ConfigurationProperties.GetProperty("resetConnectionCount").Value = (true); - ConnectorFacade facade2 = - ConnectorFacadeFactory.GetInstance().NewInstance(config2); - facade2.Schema(); //force instantiation - } - - APIConfiguration config = - info1.CreateDefaultAPIConfiguration(); - - config.ConnectorPoolConfiguration.MinIdle = (0); - config.ConnectorPoolConfiguration.MaxIdle = (0); - - ConnectorFacade facade1 = - ConnectorFacadeFactory.GetInstance().NewInstance(config); - - OperationOptionsBuilder builder = new OperationOptionsBuilder(); - builder.SetOption("testPooling", "true"); - OperationOptions options = builder.Build(); - ICollection attrs = CollectionUtil.NewReadOnlySet(); - Assert.AreEqual("1", facade1.Create(ObjectClass.ACCOUNT, attrs, options).GetUidValue()); - Assert.AreEqual("2", facade1.Create(ObjectClass.ACCOUNT, attrs, options).GetUidValue()); - Assert.AreEqual("3", facade1.Create(ObjectClass.ACCOUNT, attrs, options).GetUidValue()); - Assert.AreEqual("4", facade1.Create(ObjectClass.ACCOUNT, attrs, options).GetUidValue()); - config = - info1.CreateDefaultAPIConfiguration(); - config.ConnectorPoolConfiguration.MinIdle = (1); - config.ConnectorPoolConfiguration.MaxIdle = (2); - facade1 = - ConnectorFacadeFactory.GetInstance().NewInstance(config); - Assert.AreEqual("5", facade1.Create(ObjectClass.ACCOUNT, attrs, options).GetUidValue()); - Assert.AreEqual("5", facade1.Create(ObjectClass.ACCOUNT, attrs, options).GetUidValue()); - Assert.AreEqual("5", facade1.Create(ObjectClass.ACCOUNT, attrs, options).GetUidValue()); - Assert.AreEqual("5", facade1.Create(ObjectClass.ACCOUNT, attrs, options).GetUidValue()); - } - - [Test] - public void TestScripting() - { - ConnectorInfoManager manager = - GetConnectorInfoManager(); - ConnectorInfo info = - FindConnectorInfo(manager, - "1.0.0.0", - "org.identityconnectors.testconnector.TstConnector"); - APIConfiguration api = info.CreateDefaultAPIConfiguration(); - - - ConnectorFacadeFactory facf = ConnectorFacadeFactory.GetInstance(); - ConnectorFacade facade = facf.NewInstance(api); - - ScriptContextBuilder builder = new ScriptContextBuilder(); - builder.AddScriptArgument("arg1", "value1"); - builder.AddScriptArgument("arg2", "value2"); - builder.ScriptLanguage = ("BOO"); - - //test that they can run the script and access the - //connector object - { - String SCRIPT = - "connector.concat(arg1,arg2)"; - builder.ScriptText = (SCRIPT); - String result = (String)facade.RunScriptOnConnector(builder.Build(), - null); - - Assert.AreEqual("value1value2", result); - } - - //test that they can access a class in the class loader - { - String SCRIPT = - "import org.identityconnectors.testconnector\n" + - "TstConnector.getVersion()"; - builder.ScriptText = (SCRIPT); - String result = (String)facade.RunScriptOnConnector(builder.Build(), - null); - Assert.AreEqual("1.0", result); - } - - //test that they cannot access a class in internal - { - Type clazz = typeof(ConfigurationPropertyImpl); - - String SCRIPT = - "import " + clazz.Namespace + "\n" + - clazz.Name + "()"; - builder.ScriptText = (SCRIPT); - try - { - facade.RunScriptOnConnector(builder.Build(), - null); - Assert.Fail("exception expected"); - } - catch (Exception e) - { - String msg = e.Message; - String expectedMessage = - "Namespace '" + clazz.Namespace + "' not found"; - Assert.IsTrue( - msg.Contains(expectedMessage), - "Unexpected message: " + msg); - } - } - - // test that they can access a class in common - { - Type clazz = typeof(ConnectorAttributeBuilder); - String SCRIPT = - "import " + clazz.Namespace + "\n" + - clazz.Name + ".Build(\"myattr\")"; - builder.ScriptText = (SCRIPT); - ConnectorAttribute attr = (ConnectorAttribute)facade.RunScriptOnConnector(builder.Build(), null); - Assert.AreEqual("myattr", attr.Name); - } - } - - protected virtual ConnectorInfoManager GetConnectorInfoManager() - { - ConnectorInfoManagerFactory fact = ConnectorInfoManagerFactory.GetInstance(); - ConnectorInfoManager manager = fact.GetLocalManager(); - return manager; - } - - protected virtual void ShutdownConnnectorInfoManager() - { - ConnectorFacadeFactory.GetInstance().Dispose(); - } - } - - [TestFixture] - public class RemoteConnectorInfoManagerClearTests : ConnectorInfoManagerTests - { - - private ConnectorServer _server; - - protected override ConnectorInfoManager GetConnectorInfoManager() - { - TestUtil.InitializeLogging(); - - GuardedString str = new GuardedString(); - str.AppendChar('c'); - str.AppendChar('h'); - str.AppendChar('a'); - str.AppendChar('n'); - str.AppendChar('g'); - str.AppendChar('e'); - str.AppendChar('i'); - str.AppendChar('t'); - -#if DEBUG - const int PORT = 8758; -#else - const int PORT = 8759; -#endif - _server = ConnectorServer.NewInstance(); - _server.Port = PORT; - _server.IfAddress = (IOUtil.GetIPAddress("127.0.0.1")); - _server.KeyHash = str.GetBase64SHA1Hash(); - _server.Start(); - //while ( true ) { - // Thread.Sleep(1000); - //} - ConnectorInfoManagerFactory fact = ConnectorInfoManagerFactory.GetInstance(); - - RemoteFrameworkConnectionInfo connInfo = new - RemoteFrameworkConnectionInfo("127.0.0.1", PORT, str); - - ConnectorInfoManager manager = fact.GetRemoteManager(connInfo); - - return manager; - } - - protected override void ShutdownConnnectorInfoManager() - { - if (_server != null) - { - _server.Stop(); - _server = null; - } - } - } - - internal class MyCertificateValidationCallback - { - public bool Validate(Object sender, - X509Certificate certificate, - X509Chain chain, - SslPolicyErrors sslPolicyErrors) - { - Trace.TraceInformation("validating: " + certificate.Subject); - return true; - } - } - - [TestFixture] - public class RemoteConnectorInfoManagerSSLTests : ConnectorInfoManagerTests - { - - //To generate test certificate do the following: - // - //makecert -r -pe -n "CN=localhost" -ss TestCertificateStore -sr currentuser -sky exchange - // - //In MMC, go to the certificate, export - private ConnectorServer _server; - private const String CERT_PATH = "../../../server.pfx"; - protected override ConnectorInfoManager GetConnectorInfoManager() - { - TestUtil.InitializeLogging(); - - GuardedString str = new GuardedString(); - str.AppendChar('c'); - str.AppendChar('h'); - str.AppendChar('a'); - str.AppendChar('n'); - str.AppendChar('g'); - str.AppendChar('e'); - str.AppendChar('i'); - str.AppendChar('t'); - -#if DEBUG - const int PORT = 8762; -#else - const int PORT = 8761; -#endif - - /*X509Store store = new X509Store("TestCertificateStore", - StoreLocation.CurrentUser); - store.Open(OpenFlags.ReadOnly|OpenFlags.OpenExistingOnly); - X509Certificate certificate = store.Certificates[0]; - store.Close();*/ - - X509Certificate2 certificate = new - X509Certificate2(CERT_PATH, - "changeit"); - //Trace.TraceInformation("certificate: "+certificate); - _server = ConnectorServer.NewInstance(); - _server.Port = PORT; - _server.KeyHash = str.GetBase64SHA1Hash(); - _server.IfAddress = (IOUtil.GetIPAddress("localhost")); - _server.UseSSL = true; - _server.ServerCertificate = certificate; - _server.Start(); - //while ( true ) { - // Thread.Sleep(1000); - //} - ConnectorInfoManagerFactory fact = ConnectorInfoManagerFactory.GetInstance(); - MyCertificateValidationCallback - callback = new MyCertificateValidationCallback(); - RemoteFrameworkConnectionInfo connInfo = new - RemoteFrameworkConnectionInfo("localhost", - PORT, - str, - true, - callback.Validate, - 60000); - - ConnectorInfoManager manager = fact.GetRemoteManager(connInfo); - - return manager; - } - - protected override void ShutdownConnnectorInfoManager() - { - if (_server != null) - { - _server.Stop(); - _server = null; - } - } - } -} \ No newline at end of file diff --git a/FrameworkTests/ExceptionUtilTests.cs b/FrameworkTests/ExceptionUtilTests.cs deleted file mode 100644 index feb4ac8..0000000 --- a/FrameworkTests/ExceptionUtilTests.cs +++ /dev/null @@ -1,117 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Linq; -using System.Text; -using NUnit.Framework; -using Org.IdentityConnectors.Test.Common; -using System.Diagnostics; -using Org.IdentityConnectors.Framework.Impl; - -namespace FrameworkTests -{ - /// - /// Contains helper function to verify the output of . - /// - internal class ExceptionUtilTestHelpers - { - /// - /// Tests whether the is originated from the same function as in which the - /// was captured. - /// - /// The exception to test. - /// The captured stack trace to test against. - public static void AssertStackTrace(Exception exception, StackTrace stackTrace) - { - Trace.TraceInformation("Stack trace from the failing method: {0}", stackTrace.ToString()); - Trace.TraceInformation("Exception stack trace: {0}", exception.StackTrace); - - string fullST = stackTrace.ToString(); - int newLinePos = fullST.IndexOf(Environment.NewLine); - string failingMethodExpected = fullST.Substring(0, (newLinePos == -1) ? fullST.Length : newLinePos); - - newLinePos = exception.StackTrace.IndexOf(Environment.NewLine); - string failingMethodActual = exception.StackTrace.Substring(0, (newLinePos == -1) ? fullST.Length : newLinePos); - - //check if the first line of the stack trace fetched from the failing method is contained in the - //first line of the exception's stack trace, i.e. the method which threw the exception is in the - //stack trace of the exception - Assert.That(failingMethodActual.Contains(failingMethodExpected)); - } - } - - [TestFixture] - public class ExceptionUtilTests - { - [Test] - public void TestPreserveStackTrace() - { - StackTrace stackTrace = null; - try - { - try - { - Action bar = () => - { - try - { - //delegate to the failing method - Action foo = () => - { - stackTrace = new StackTrace(false); - throw new InvalidOperationException(); - }; - - foo(); - - Assert.Fail("Exception was not thrown - 1"); - } - catch (InvalidOperationException iopex) - { - //wrap the exception to make sure that there is an - //inner exception that can be re-thrown later on - throw new ArgumentException(string.Empty, iopex); - }; - }; - - bar(); - - Assert.Fail("Exception was not thrown - 2"); - } - catch (ArgumentException aex) - { - //preserve the stack trace of the nested exception and re-throw it - ExceptionUtil.PreserveStackTrace(aex.InnerException); - throw aex.InnerException; - } - - Assert.Fail("Exception was not thrown - 3"); - } - catch (InvalidOperationException iopex) - { - ExceptionUtilTestHelpers.AssertStackTrace(iopex, stackTrace); - } - } - } -} diff --git a/FrameworkTests/FilterTranslatorTests.cs b/FrameworkTests/FilterTranslatorTests.cs deleted file mode 100644 index da94231..0000000 --- a/FrameworkTests/FilterTranslatorTests.cs +++ /dev/null @@ -1,643 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 NUnit.Framework; -using NUnit.Framework.SyntaxHelpers; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Common.Objects.Filters; -namespace FrameworkTests -{ - - internal class AllFiltersTranslator : AbstractFilterTranslator - { - protected override String CreateAndExpression(String leftExpression, String rightExpression) - { - return "( & " + leftExpression + " " + rightExpression + " )"; - } - - protected override String CreateOrExpression(String leftExpression, String rightExpression) - { - return "( | " + leftExpression + " " + rightExpression + " )"; - } - - protected override String CreateContainsExpression(ContainsFilter filter, bool not) - { - String rv = "( CONTAINS " + filter.GetName() + " " + filter.GetValue() + " )"; - return Not(rv, not); - } - - protected override String CreateEndsWithExpression(EndsWithFilter filter, bool not) - { - String rv = "( ENDS-WITH " + filter.GetName() + " " + filter.GetValue() + " )"; - return Not(rv, not); - } - - protected override String CreateEqualsExpression(EqualsFilter filter, bool not) - { - String rv = "( = " + filter.GetAttribute().Name + " [" + filter.GetAttribute().Value[0] + "] )"; - return Not(rv, not); - } - - protected override String CreateGreaterThanExpression(GreaterThanFilter filter, bool not) - { - String rv = "( > " + filter.GetName() + " " + filter.GetValue() + " )"; - return Not(rv, not); - } - - protected override String CreateGreaterThanOrEqualExpression(GreaterThanOrEqualFilter filter, bool not) - { - String rv = "( >= " + filter.GetName() + " " + filter.GetValue() + " )"; - return Not(rv, not); - } - - protected override String CreateLessThanExpression(LessThanFilter filter, bool not) - { - String rv = "( < " + filter.GetName() + " " + filter.GetValue() + " )"; - return Not(rv, not); - } - - protected override String CreateLessThanOrEqualExpression(LessThanOrEqualFilter filter, bool not) - { - String rv = "( <= " + filter.GetName() + " " + filter.GetValue() + " )"; - return Not(rv, not); - } - - protected override String CreateStartsWithExpression(StartsWithFilter filter, bool not) - { - String rv = "( STARTS-WITH " + filter.GetName() + " " + filter.GetValue() + " )"; - return Not(rv, not); - } - protected override String CreateContainsAllValuesExpression(ContainsAllValuesFilter filter, bool not) - { - String rv = "( CONTAINS-ALL-VALUES " + filter.GetAttribute() + " )"; - return Not(rv, not); - } - private String Not(String orig, bool not) - { - if (not) - { - return "( ! " + orig + " )"; - } - else - { - return orig; - } - } - } - - /// - /// Everything but Or - /// - internal class NoOrTranslator : AllFiltersTranslator - { - protected override String CreateOrExpression(String leftExpression, String rightExpression) - { - return null; - } - } - /// - /// Everything but EndsWith - /// - internal class NoEndsWithTranslator : AllFiltersTranslator - { - protected override String CreateEndsWithExpression(EndsWithFilter filter, bool not) - { - return null; - } - } - /// - /// Everything but EndsWith,Or - /// - internal class NoEndsWithNoOrTranslator : AllFiltersTranslator - { - protected override String CreateOrExpression(String leftExpression, String rightExpression) - { - return null; - } - protected override String CreateEndsWithExpression(EndsWithFilter filter, bool not) - { - return null; - } - } - - /// - /// Everything but And - /// - internal class NoAndTranslator : AllFiltersTranslator - { - protected override String CreateAndExpression(String leftExpression, String rightExpression) - { - return null; - } - } - /// - /// Everything but And - /// - internal class NoAndNoEndsWithTranslator : AllFiltersTranslator - { - protected override String CreateAndExpression(String leftExpression, String rightExpression) - { - return null; - } - protected override String CreateEndsWithExpression(EndsWithFilter filter, bool not) - { - return null; - } - - } - /// - /// Everything but And - /// - internal class NoAndNoOrNoEndsWithTranslator : AllFiltersTranslator - { - protected override String CreateAndExpression(String leftExpression, String rightExpression) - { - return null; - } - protected override String CreateEndsWithExpression(EndsWithFilter filter, bool not) - { - return null; - } - protected override String CreateOrExpression(String leftExpression, String rightExpression) - { - return null; - } - - } - [TestFixture] - public class FilterTranslatorTests - { - - /// - /// Test all operations when everything is fully implemented. - /// - /// - /// Test not normalization as well. - /// - [Test] - public void TestBasics() - { - ConnectorAttribute attribute = - ConnectorAttributeBuilder.Build("att-name", "att-value"); - ConnectorAttribute attribute2 = - ConnectorAttributeBuilder.Build("att-name2", "att-value2"); - AllFiltersTranslator translator = new - AllFiltersTranslator(); - - { - Filter filter = - FilterBuilder.Contains(attribute); - String expected = "( CONTAINS att-name att-value )"; - String actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - - filter = FilterBuilder.Not(filter); - expected = "( ! " + expected + " )"; - actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - } - - { - Filter filter = - FilterBuilder.EndsWith(attribute); - String expected = "( ENDS-WITH att-name att-value )"; - String actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - - filter = FilterBuilder.Not(filter); - expected = "( ! " + expected + " )"; - actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - } - - { - Filter filter = - FilterBuilder.EqualTo(attribute); - String expected = "( = att-name [att-value] )"; - String actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - - filter = FilterBuilder.Not(filter); - expected = "( ! " + expected + " )"; - actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - } - - { - Filter filter = - FilterBuilder.GreaterThan(attribute); - String expected = "( > att-name att-value )"; - String actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - - filter = FilterBuilder.Not(filter); - expected = "( ! " + expected + " )"; - actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - } - - { - Filter filter = - FilterBuilder.GreaterThanOrEqualTo(attribute); - String expected = "( >= att-name att-value )"; - String actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - - filter = FilterBuilder.Not(filter); - expected = "( ! " + expected + " )"; - actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - } - - { - Filter filter = - FilterBuilder.LessThan(attribute); - String expected = "( < att-name att-value )"; - String actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - - filter = FilterBuilder.Not(filter); - expected = "( ! " + expected + " )"; - actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - } - - { - Filter filter = - FilterBuilder.LessThanOrEqualTo(attribute); - String expected = "( <= att-name att-value )"; - String actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - - filter = FilterBuilder.Not(filter); - expected = "( ! " + expected + " )"; - actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - } - - { - Filter filter = - FilterBuilder.StartsWith(attribute); - String expected = "( STARTS-WITH att-name att-value )"; - String actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - - filter = FilterBuilder.Not(filter); - expected = "( ! " + expected + " )"; - actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - } - - { - Filter filter = - FilterBuilder.ContainsAllValues(attribute); - String expected = "( CONTAINS-ALL-VALUES " + attribute + " )"; - String actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - - filter = FilterBuilder.Not(filter); - expected = "( ! " + expected + " )"; - actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - } - - //and - { - Filter left = - FilterBuilder.Contains(attribute); - Filter right = - FilterBuilder.Contains(attribute2); - String expectedLeft = "( CONTAINS att-name att-value )"; - String expectedRight = "( CONTAINS att-name2 att-value2 )"; - Filter filter = - FilterBuilder.And(left, right); - String expected = - "( & " + expectedLeft + " " + expectedRight + " )"; - String actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - - filter = FilterBuilder.Not(filter); - expectedLeft = "( ! " + expectedLeft + " )"; - expectedRight = "( ! " + expectedRight + " )"; - expected = - "( | " + expectedLeft + " " + expectedRight + " )"; - actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - - } - - //or - { - Filter left = - FilterBuilder.Contains(attribute); - Filter right = - FilterBuilder.Contains(attribute2); - String expectedLeft = "( CONTAINS att-name att-value )"; - String expectedRight = "( CONTAINS att-name2 att-value2 )"; - Filter filter = - FilterBuilder.Or(left, right); - String expected = - "( | " + expectedLeft + " " + expectedRight + " )"; - String actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - - filter = FilterBuilder.Not(filter); - expectedLeft = "( ! " + expectedLeft + " )"; - expectedRight = "( ! " + expectedRight + " )"; - expected = - "( & " + expectedLeft + " " + expectedRight + " )"; - actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - } - - //double-negative - { - Filter filter = - FilterBuilder.Contains(attribute); - filter = FilterBuilder.Not(filter); - filter = FilterBuilder.Not(filter); - String expected = "( CONTAINS att-name att-value )"; - String actual = - TranslateSingle(translator, filter); - Assert.AreEqual(expected, actual); - } - - } - - /// - /// (a OR b) AND ( c OR d) needs to become - /// (a AND c) OR ( a AND d) OR (b AND c) OR (b AND d) is - /// OR is not implemented. - /// - /// - /// Otherwise it should stay - /// as-is. - /// - [Test] - public void TestDistribution() - { - Filter a = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("a", "a")); - Filter b = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("b", "b")); - Filter c = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("c", "c")); - Filter d = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("d", "d")); - - Filter filter = - FilterBuilder.And( - FilterBuilder.Or(a, b), - FilterBuilder.Or(c, d)); - String expected = "( & ( | ( CONTAINS a a ) ( CONTAINS b b ) ) ( | ( CONTAINS c c ) ( CONTAINS d d ) ) )"; - String actual = - TranslateSingle(new AllFiltersTranslator(), filter); - - Assert.AreEqual(expected, actual); - - IList results = - new NoOrTranslator().Translate(filter); - Assert.AreEqual(4, results.Count); - - Assert.AreEqual("( & ( CONTAINS a a ) ( CONTAINS c c ) )", - results[0]); - Assert.AreEqual("( & ( CONTAINS a a ) ( CONTAINS d d ) )", - results[1]); - Assert.AreEqual("( & ( CONTAINS b b ) ( CONTAINS c c ) )", - results[2]); - Assert.AreEqual("( & ( CONTAINS b b ) ( CONTAINS d d ) )", - results[3]); - } - - //test simplification - //-no leaf - [Test] - public void TestSimplifyNoLeaf() - { - Filter a = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("a", "a")); - Filter b = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("b", "b")); - Filter c = - FilterBuilder.EndsWith(ConnectorAttributeBuilder.Build("c", "c")); - Filter d = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("d", "d")); - - Filter filter = - FilterBuilder.And( - FilterBuilder.Or(a, b), - FilterBuilder.Or(c, d)); - String expected = "( | ( CONTAINS a a ) ( CONTAINS b b ) )"; - String actual = - TranslateSingle(new NoEndsWithTranslator(), filter); - Assert.AreEqual(expected, actual); - - } - //-no leaf + no or - [Test] - public void TestSimplifyNoLeafNoOr() - { - Filter a = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("a", "a")); - Filter b = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("b", "b")); - Filter c = - FilterBuilder.EndsWith(ConnectorAttributeBuilder.Build("c", "c")); - Filter d = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("d", "d")); - - Filter filter = - FilterBuilder.And( - FilterBuilder.Or(a, b), - FilterBuilder.Or(c, d)); - IList results = - new NoEndsWithNoOrTranslator().Translate(filter); - Assert.AreEqual(2, results.Count); - Assert.AreEqual("( CONTAINS a a )", - results[0]); - Assert.AreEqual("( CONTAINS b b )", - results[1]); - - } - - //-no and - [Test] - public void TestSimplifyNoAnd() - { - Filter a = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("a", "a")); - Filter b = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("b", "b")); - Filter c = - FilterBuilder.EndsWith(ConnectorAttributeBuilder.Build("c", "c")); - Filter d = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("d", "d")); - - Filter filter = - FilterBuilder.And( - FilterBuilder.Or(a, b), - FilterBuilder.Or(c, d)); - String expected = "( | ( CONTAINS a a ) ( CONTAINS b b ) )"; - String actual = - TranslateSingle(new NoAndTranslator(), filter); - Assert.AreEqual(expected, actual); - } - - //-no and+no leaf - [Test] - public void TestSimplifyNoAndNoLeaf() - { - Filter a = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("a", "a")); - Filter b = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("b", "b")); - Filter c = - FilterBuilder.EndsWith(ConnectorAttributeBuilder.Build("c", "c")); - Filter d = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("d", "d")); - - Filter filter = - FilterBuilder.And( - FilterBuilder.Or(a, b), - FilterBuilder.Or(c, d)); - String expected = "( | ( CONTAINS a a ) ( CONTAINS b b ) )"; - String actual = - TranslateSingle(new NoAndNoEndsWithTranslator(), filter); - Assert.AreEqual(expected, actual); - - a = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("a", "a")); - b = - FilterBuilder.EndsWith(ConnectorAttributeBuilder.Build("b", "b")); - c = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("c", "c")); - d = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("d", "d")); - - filter = - FilterBuilder.And( - FilterBuilder.Or(a, b), - FilterBuilder.Or(c, d)); - expected = "( | ( CONTAINS c c ) ( CONTAINS d d ) )"; - actual = - TranslateSingle(new NoAndNoEndsWithTranslator(), filter); - Assert.AreEqual(expected, actual); - - a = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("a", "a")); - b = - FilterBuilder.EndsWith(ConnectorAttributeBuilder.Build("b", "b")); - c = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("c", "c")); - d = - FilterBuilder.EndsWith(ConnectorAttributeBuilder.Build("d", "d")); - - filter = - FilterBuilder.And( - FilterBuilder.Or(a, b), - FilterBuilder.Or(c, d)); - IList results = - new NoAndNoEndsWithTranslator().Translate(filter); - Assert.AreEqual(0, results.Count); - } - - //-no and, no or, no leaf - [Test] - public void TestSimplifyNoAndNoOrNoLeaf() - { - Filter a = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("a", "a")); - Filter b = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("b", "b")); - Filter c = - FilterBuilder.EndsWith(ConnectorAttributeBuilder.Build("c", "c")); - Filter d = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("d", "d")); - - Filter filter = - FilterBuilder.And( - FilterBuilder.Or(a, b), - FilterBuilder.Or(c, d)); - IList results = - new NoAndNoOrNoEndsWithTranslator().Translate(filter); - Assert.AreEqual(2, results.Count); - Assert.AreEqual("( CONTAINS a a )", - results[0]); - Assert.AreEqual("( CONTAINS b b )", - results[1]); - - a = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("a", "a")); - b = - FilterBuilder.EndsWith(ConnectorAttributeBuilder.Build("b", "b")); - c = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("c", "c")); - d = - FilterBuilder.Contains(ConnectorAttributeBuilder.Build("d", "d")); - filter = - FilterBuilder.And( - FilterBuilder.Or(a, b), - FilterBuilder.Or(c, d)); - results = - new NoAndNoOrNoEndsWithTranslator().Translate(filter); - Assert.AreEqual(2, results.Count); - Assert.AreEqual("( CONTAINS c c )", - results[0]); - Assert.AreEqual("( CONTAINS d d )", - results[1]); - } - - private static String TranslateSingle(AbstractFilterTranslator translator, - Filter filter) - { - IList translated = - translator.Translate(filter); - Assert.AreEqual(1, translated.Count); - return translated[0]; - } - } -} \ No newline at end of file diff --git a/FrameworkTests/FrameworkTests.csproj b/FrameworkTests/FrameworkTests.csproj deleted file mode 100644 index ff902a8..0000000 --- a/FrameworkTests/FrameworkTests.csproj +++ /dev/null @@ -1,172 +0,0 @@ - - - - {32804F5A-812C-4FA6-835C-BDAE5B24D355} - Debug - AnyCPU - Library - FrameworkTests - FrameworkTests - FrameworkTests - v3.5 - - - bin\Debug\ - True - Full - False - True - DEBUG;TRACE - - - - - bin\Release\ - False - None - True - False - TRACE - - - - - - - 3.5 - - - - 3.5 - - - - 3.5 - - - - - - - - - - - - Code - - - - - - - - - - - - - - - - - - Always - - - - - {F140E8DA-52B4-4159-992A-9DA10EA8EEFB} - Common - - - {8B24461B-456A-4032-89A1-CD418F7B5B62} - Framework - - - {5B011775-B121-4EEE-A410-BA2D2F5BFB8B} - FrameworkInternal - - - {E6A207D2-E083-41BF-B522-D9D3EC09323E} - TestCommon - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/FrameworkTests/GuardedByteArrayTests.cs b/FrameworkTests/GuardedByteArrayTests.cs deleted file mode 100755 index 17f05c4..0000000 --- a/FrameworkTests/GuardedByteArrayTests.cs +++ /dev/null @@ -1,105 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Security; -using System.Runtime.InteropServices; -using System.Text; -using Org.IdentityConnectors.Common.Security; -using Org.IdentityConnectors.Framework.Common.Serializer; -using NUnit.Framework; -using NUnit.Framework.SyntaxHelpers; - -namespace FrameworkTests -{ - [TestFixture] - public class GuardedByteArrayTests - { - [Test] - public void TestBasics() - { - GuardedByteArray ss = new GuardedByteArray(); - ss.AppendByte(0x00); - ss.AppendByte(0x01); - ss.AppendByte(0x02); - byte[] decrypted = DecryptToByteArray(ss); - Assert.AreEqual(new byte[] { 0x00, 0x01, 0x02 }, decrypted); - String hash = ss.GetBase64SHA1Hash(); - Assert.IsTrue(ss.VerifyBase64SHA1Hash(hash)); - ss.AppendByte(0x03); - Assert.IsFalse(ss.VerifyBase64SHA1Hash(hash)); - } - [Test] - public void TestRange() - { - - for (byte i = 0; i < 0xFF; i++) - { - byte expected = i; - GuardedByteArray gba = new GuardedByteArray(); - gba = (GuardedByteArray)SerializerUtil.CloneObject(gba); - gba.AppendByte(i); - gba.Access(clearChars => - { - int v = (byte)clearChars[0]; - Assert.AreEqual(expected, v); - }); - - } - } - - [Test] - public void TestEquals() - { - GuardedByteArray arr1 = new GuardedByteArray(); - GuardedByteArray arr2 = new GuardedByteArray(); - Assert.AreEqual(arr1, arr2); - arr2.AppendByte(0x02); - Assert.AreNotEqual(arr1, arr2); - arr1.AppendByte(0x02); - Assert.AreEqual(arr1, arr2); - } - - - /// - /// Highly insecure method! Do not do this in production - /// code. - /// - /// - /// This is only for test purposes - /// - private byte[] DecryptToByteArray(GuardedByteArray str) - { - byte[] result = null; - str.Access( - array => - { - result = new byte[array.Length]; - for (int i = 0; i < array.Length; i++) - { - result[i] = array[i]; - } - }); - return result; - } - } -} \ No newline at end of file diff --git a/FrameworkTests/GuardedStringTests.cs b/FrameworkTests/GuardedStringTests.cs deleted file mode 100644 index 75cd8a4..0000000 --- a/FrameworkTests/GuardedStringTests.cs +++ /dev/null @@ -1,107 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Security; -using System.Runtime.InteropServices; -using System.Text; -using Org.IdentityConnectors.Common.Security; -using Org.IdentityConnectors.Framework.Common.Serializer; -using NUnit.Framework; -using NUnit.Framework.SyntaxHelpers; - -namespace FrameworkTests -{ - [TestFixture] - public class GuardedStringTests - { - [Test] - public void TestBasics() - { - GuardedString ss = new GuardedString(); - ss.AppendChar('f'); - ss.AppendChar('o'); - ss.AppendChar('o'); - ss.AppendChar('b'); - ss.AppendChar('a'); - ss.AppendChar('r'); - String decrypted = DecryptToString(ss); - Assert.AreEqual("foobar", decrypted); - String hash = ss.GetBase64SHA1Hash(); - Assert.IsTrue(ss.VerifyBase64SHA1Hash(hash)); - ss.AppendChar('2'); - Assert.IsFalse(ss.VerifyBase64SHA1Hash(hash)); - } - [Test] - public void TestUnicode() - { - - for (int i = 0; i < 0xFFFF; i++) - { - int expected = i; - char c = (char)i; - GuardedString gs = new GuardedString(); - gs = (GuardedString)SerializerUtil.CloneObject(gs); - gs.AppendChar(c); - gs.Access(clearChars => - { - int v = (int)clearChars[0]; - Assert.AreEqual(expected, v); - }); - - } - } - - [Test] - public void TestEquals() - { - GuardedString str1 = new GuardedString(); - GuardedString str2 = new GuardedString(); - Assert.AreEqual(str1, str2); - str2.AppendChar('2'); - Assert.AreNotEqual(str1, str2); - str1.AppendChar('2'); - Assert.AreEqual(str1, str2); - } - - /// - /// Highly insecure method! Do not do this in production - /// code. - /// - /// - /// This is only for test purposes - /// - private String DecryptToString(GuardedString str) - { - StringBuilder buf = new StringBuilder(); - str.Access( - array => - { - for (int i = 0; i < array.Length; i++) - { - buf.Append(array[i]); - } - }); - return buf.ToString(); - } - } -} \ No newline at end of file diff --git a/FrameworkTests/LocaleTests.cs b/FrameworkTests/LocaleTests.cs deleted file mode 100644 index 3de09b8..0000000 --- a/FrameworkTests/LocaleTests.cs +++ /dev/null @@ -1,213 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 NUnit.Framework; -using NUnit.Framework.SyntaxHelpers; -using System.Globalization; -using System.Collections.Generic; -using Org.IdentityConnectors.Common; -namespace FrameworkTests -{ - [TestFixture] - public class LocaleTests - { - - - [Test] - public void TestJava2CSharp() - { - HashSet - cultures = new HashSet(CultureInfo.GetCultures(CultureTypes.AllCultures)); - - TestJavaLocale(cultures, new Locale("ar", "", ""), "Arabic"); - TestJavaLocale(cultures, new Locale("be", "", ""), "Belarusian"); - TestJavaLocale(cultures, new Locale("bg", "", ""), "Bulgarian"); - TestJavaLocale(cultures, new Locale("ca", "", ""), "Catalan"); - TestJavaLocale(cultures, new Locale("cs", "", ""), "Czech"); - TestJavaLocale(cultures, new Locale("da", "", ""), "Danish"); - TestJavaLocale(cultures, new Locale("de", "", ""), "German"); - TestJavaLocale(cultures, new Locale("el", "", ""), "Greek"); - TestJavaLocale(cultures, new Locale("en", "", ""), "English"); - TestJavaLocale(cultures, new Locale("es", "", ""), "Spanish"); - TestJavaLocale(cultures, new Locale("et", "", ""), "Estonian"); - TestJavaLocale(cultures, new Locale("fi", "", ""), "Finnish"); - TestJavaLocale(cultures, new Locale("fr", "", ""), "French"); - TestJavaLocale(cultures, new Locale("hr", "", ""), "Croatian"); - TestJavaLocale(cultures, new Locale("hu", "", ""), "Hungarian"); - TestJavaLocale(cultures, new Locale("is", "", ""), "Icelandic"); - TestJavaLocale(cultures, new Locale("it", "", ""), "Italian"); - TestJavaLocale(cultures, new Locale("iw", "", ""), "Hebrew"); - TestJavaLocale(cultures, new Locale("ja", "", ""), "Japanese"); - TestJavaLocale(cultures, new Locale("ko", "", ""), "Korean"); - TestJavaLocale(cultures, new Locale("lt", "", ""), "Lithuanian"); - TestJavaLocale(cultures, new Locale("lv", "", ""), "Latvian"); - TestJavaLocale(cultures, new Locale("mk", "", ""), "Macedonian"); - TestJavaLocale(cultures, new Locale("nl", "", ""), "Dutch"); - TestJavaLocale(cultures, new Locale("no", "", ""), "Norwegian"); - TestJavaLocale(cultures, new Locale("pl", "", ""), "Polish"); - TestJavaLocale(cultures, new Locale("pt", "", ""), "Portuguese"); - TestJavaLocale(cultures, new Locale("ro", "", ""), "Romanian"); - TestJavaLocale(cultures, new Locale("ru", "", ""), "Russian"); - TestJavaLocale(cultures, new Locale("sk", "", ""), "Slovak"); - TestJavaLocale(cultures, new Locale("sl", "", ""), "Slovenian"); - TestJavaLocale(cultures, new Locale("sq", "", ""), "Albanian"); - TestJavaLocale(cultures, new Locale("sr", "", ""), "Serbian"); - TestJavaLocale(cultures, new Locale("sv", "", ""), "Swedish"); - TestJavaLocale(cultures, new Locale("th", "", ""), "Thai"); - TestJavaLocale(cultures, new Locale("tr", "", ""), "Turkish"); - TestJavaLocale(cultures, new Locale("uk", "", ""), "Ukrainian"); - TestJavaLocale(cultures, new Locale("vi", "", ""), "Vietnamese"); - TestJavaLocale(cultures, new Locale("zh", "", ""), "Chinese"); - TestJavaLocale(cultures, new Locale("ar", "AE", ""), "Arabic (United Arab Emirates)"); - TestJavaLocale(cultures, new Locale("ar", "BH", ""), "Arabic (Bahrain)"); - TestJavaLocale(cultures, new Locale("ar", "DZ", ""), "Arabic (Algeria)"); - TestJavaLocale(cultures, new Locale("ar", "EG", ""), "Arabic (Egypt)"); - TestJavaLocale(cultures, new Locale("ar", "IQ", ""), "Arabic (Iraq)"); - TestJavaLocale(cultures, new Locale("ar", "JO", ""), "Arabic (Jordan)"); - TestJavaLocale(cultures, new Locale("ar", "KW", ""), "Arabic (Kuwait)"); - TestJavaLocale(cultures, new Locale("ar", "LB", ""), "Arabic (Lebanon)"); - TestJavaLocale(cultures, new Locale("ar", "LY", ""), "Arabic (Libya)"); - TestJavaLocale(cultures, new Locale("ar", "MA", ""), "Arabic (Morocco)"); - TestJavaLocale(cultures, new Locale("ar", "OM", ""), "Arabic (Oman)"); - TestJavaLocale(cultures, new Locale("ar", "QA", ""), "Arabic (Qatar)"); - TestJavaLocale(cultures, new Locale("ar", "SA", ""), "Arabic (Saudi Arabia)"); - TestJavaLocale(cultures, - new Locale("ar", "SD", ""), - "Arabic (Sudan)", - new Locale("ar")); - TestJavaLocale(cultures, new Locale("ar", "SY", ""), "Arabic (Syria)"); - TestJavaLocale(cultures, new Locale("ar", "TN", ""), "Arabic (Tunisia)"); - TestJavaLocale(cultures, new Locale("ar", "YE", ""), "Arabic (Yemen)"); - TestJavaLocale(cultures, new Locale("be", "BY", ""), "Belarusian (Belarus)"); - TestJavaLocale(cultures, new Locale("bg", "BG", ""), "Bulgarian (Bulgaria)"); - TestJavaLocale(cultures, new Locale("ca", "ES", ""), "Catalan (Spain)"); - TestJavaLocale(cultures, new Locale("cs", "CZ", ""), "Czech (Czech Republic)"); - TestJavaLocale(cultures, new Locale("da", "DK", ""), "Danish (Denmark)"); - TestJavaLocale(cultures, new Locale("de", "AT", ""), "German (Austria)"); - TestJavaLocale(cultures, new Locale("de", "CH", ""), "German (Switzerland)"); - TestJavaLocale(cultures, new Locale("de", "DE", ""), "German (Germany)"); - TestJavaLocale(cultures, new Locale("de", "LU", ""), "German (Luxembourg)"); - TestJavaLocale(cultures, new Locale("el", "GR", ""), "Greek (Greece)"); - TestJavaLocale(cultures, new Locale("en", "AU", ""), "English (Australia)"); - TestJavaLocale(cultures, new Locale("en", "CA", ""), "English (Canada)"); - TestJavaLocale(cultures, new Locale("en", "GB", ""), "English (United Kingdom)"); - TestJavaLocale(cultures, new Locale("en", "IE", ""), "English (Ireland)"); - TestJavaLocale(cultures, new Locale("en", "IN", ""), - "English (India)", - new Locale("en")); - TestJavaLocale(cultures, new Locale("en", "NZ", ""), "English (New Zealand)"); - TestJavaLocale(cultures, new Locale("en", "US", ""), "English (United States)"); - TestJavaLocale(cultures, new Locale("en", "ZA", ""), "English (South Africa)"); - TestJavaLocale(cultures, new Locale("es", "AR", ""), "Spanish (Argentina)"); - TestJavaLocale(cultures, new Locale("es", "BO", ""), "Spanish (Bolivia)"); - TestJavaLocale(cultures, new Locale("es", "CL", ""), "Spanish (Chile)"); - TestJavaLocale(cultures, new Locale("es", "CO", ""), "Spanish (Colombia)"); - TestJavaLocale(cultures, new Locale("es", "CR", ""), "Spanish (Costa Rica)"); - TestJavaLocale(cultures, new Locale("es", "DO", ""), "Spanish (Dominican Republic)"); - TestJavaLocale(cultures, new Locale("es", "EC", ""), "Spanish (Ecuador)"); - TestJavaLocale(cultures, new Locale("es", "ES", ""), "Spanish (Spain)"); - TestJavaLocale(cultures, new Locale("es", "GT", ""), "Spanish (Guatemala)"); - TestJavaLocale(cultures, new Locale("es", "HN", ""), "Spanish (Honduras)"); - TestJavaLocale(cultures, new Locale("es", "MX", ""), "Spanish (Mexico)"); - TestJavaLocale(cultures, new Locale("es", "NI", ""), "Spanish (Nicaragua)"); - TestJavaLocale(cultures, new Locale("es", "PA", ""), "Spanish (Panama)"); - TestJavaLocale(cultures, new Locale("es", "PE", ""), "Spanish (Peru)"); - TestJavaLocale(cultures, new Locale("es", "PR", ""), "Spanish (Puerto Rico)"); - TestJavaLocale(cultures, new Locale("es", "PY", ""), "Spanish (Paraguay)"); - TestJavaLocale(cultures, new Locale("es", "SV", ""), "Spanish (El Salvador)"); - TestJavaLocale(cultures, new Locale("es", "UY", ""), "Spanish (Uruguay)"); - TestJavaLocale(cultures, new Locale("es", "VE", ""), "Spanish (Venezuela)"); - TestJavaLocale(cultures, new Locale("et", "EE", ""), "Estonian (Estonia)"); - TestJavaLocale(cultures, new Locale("fi", "FI", ""), "Finnish (Finland)"); - TestJavaLocale(cultures, new Locale("fr", "BE", ""), "French (Belgium)"); - TestJavaLocale(cultures, new Locale("fr", "CA", ""), "French (Canada)"); - TestJavaLocale(cultures, new Locale("fr", "CH", ""), "French (Switzerland)"); - TestJavaLocale(cultures, new Locale("fr", "FR", ""), "French (France)"); - TestJavaLocale(cultures, new Locale("fr", "LU", ""), "French (Luxembourg)"); - TestJavaLocale(cultures, new Locale("hi", "IN", ""), "Hindi (India)"); - TestJavaLocale(cultures, new Locale("hr", "HR", ""), "Croatian (Croatia)"); - TestJavaLocale(cultures, new Locale("hu", "HU", ""), "Hungarian (Hungary)"); - TestJavaLocale(cultures, new Locale("is", "IS", ""), "Icelandic (Iceland)"); - TestJavaLocale(cultures, new Locale("it", "CH", ""), "Italian (Switzerland)"); - TestJavaLocale(cultures, new Locale("it", "IT", ""), "Italian (Italy)"); - TestJavaLocale(cultures, new Locale("iw", "IL", ""), "Hebrew (Israel)"); - TestJavaLocale(cultures, new Locale("ja", "JP", ""), "Japanese (Japan)"); - TestJavaLocale(cultures, new Locale("ko", "KR", ""), "Korean (South Korea)"); - TestJavaLocale(cultures, new Locale("lt", "LT", ""), "Lithuanian (Lithuania)"); - TestJavaLocale(cultures, new Locale("lv", "LV", ""), "Latvian (Latvia)"); - TestJavaLocale(cultures, new Locale("mk", "MK", ""), "Macedonian (Macedonia)"); - TestJavaLocale(cultures, new Locale("nl", "BE", ""), "Dutch (Belgium)"); - TestJavaLocale(cultures, new Locale("nl", "NL", ""), "Dutch (Netherlands)"); - TestJavaLocale(cultures, new Locale("no", "NO", ""), "Norwegian (Norway)"); - TestJavaLocale(cultures, new Locale("no", "NO", "NY"), "Norwegian (Norway,Nynorsk)"); - TestJavaLocale(cultures, new Locale("pl", "PL", ""), "Polish (Poland)"); - TestJavaLocale(cultures, new Locale("pt", "BR", ""), "Portuguese (Brazil)"); - TestJavaLocale(cultures, new Locale("pt", "PT", ""), "Portuguese (Portugal)"); - TestJavaLocale(cultures, new Locale("ro", "RO", ""), "Romanian (Romania)"); - TestJavaLocale(cultures, new Locale("ru", "RU", ""), "Russian (Russia)"); - TestJavaLocale(cultures, new Locale("sk", "SK", ""), "Slovak (Slovakia)"); - TestJavaLocale(cultures, new Locale("sl", "SI", ""), "Slovenian (Slovenia)"); - TestJavaLocale(cultures, new Locale("sq", "AL", ""), "Albanian (Albania)"); - TestJavaLocale(cultures, new Locale("sr", "BA", ""), - "Serbian (Bosnia and Herzegovina)", - new Locale("sr")); - TestJavaLocale(cultures, new Locale("sr", "CS", ""), - "Serbian (Serbia and Montenegro)", - new Locale("sr")); - TestJavaLocale(cultures, new Locale("sv", "SE", ""), "Swedish (Sweden)"); - TestJavaLocale(cultures, new Locale("th", "TH", ""), "Thai (Thailand)"); - TestJavaLocale(cultures, new Locale("th", "TH", "TH"), - "Thai (Thailand,TH)", - new Locale("th", "TH")); - TestJavaLocale(cultures, new Locale("tr", "TR", ""), "Turkish (Turkey)"); - TestJavaLocale(cultures, new Locale("uk", "UA", ""), "Ukrainian (Ukraine)"); - TestJavaLocale(cultures, new Locale("vi", "VN", ""), "Vietnamese (Vietnam)"); - TestJavaLocale(cultures, new Locale("zh", "CN", ""), "Chinese (China)"); - TestJavaLocale(cultures, new Locale("zh", "HK", ""), "Chinese (Hong Kong)"); - TestJavaLocale(cultures, new Locale("zh", "TW", ""), "Chinese (Taiwan)"); - - //foreach (CultureInfo info in cultures) { - // Console.WriteLine("remaining: "+info+" "+info.DisplayName+" "+info.TwoLetterISOLanguageName); - //} - } - private void TestJavaLocale(HashSet cultures, - Locale original, - String display) - { - TestJavaLocale(cultures, original, display, null); - } - private void TestJavaLocale(HashSet cultures, - Locale original, - String display, - Locale expected) - { - if (expected == null) - { - expected = original; - } - CultureInfo cinfo = original.ToCultureInfo(); - Locale actual = Locale.FindLocale(cinfo); - Assert.AreEqual(expected, actual, display + " (" + original + ") " + " didn't map"); - } - } -} \ No newline at end of file diff --git a/FrameworkTests/MockConnector.cs b/FrameworkTests/MockConnector.cs deleted file mode 100755 index e3aefa4..0000000 --- a/FrameworkTests/MockConnector.cs +++ /dev/null @@ -1,341 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 NUnit.Framework; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Common.Security; -using Org.IdentityConnectors.Framework.Common.Exceptions; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Common.Objects.Filters; -using Org.IdentityConnectors.Framework.Spi; -using Org.IdentityConnectors.Framework.Spi.Operations; - -namespace FrameworkTests -{ - - public class MockConnector : Connector, SchemaOp - { - - /// - /// Represents a call to a connector method. - /// - public class Call - { - - private readonly string methodName; - private readonly object[] args; - - public Call(string methodName, params object[] args) - { - this.methodName = methodName; - this.args = args; - } - - public string MethodName - { - get - { - return methodName; - } - } - - public object[] Arguments - { - get - { - return this.args; - } - } - } - - // need to keep track of when methods are called an their parameters.. - private static IList callPattern = new List(); - - private Configuration _config; - - public void Dispose() - { - AddCall("Dispose"); - } - - public Schema Schema() - { - AddCall("Schema"); - return null; - } - - public void Init(Configuration cfg) - { - _config = cfg; - AddCall("Init", cfg); - } - - public Configuration getConfiguration() - { - return _config; - } - - /// - /// Clear the call pattern. - /// - public static void Reset() - { - callPattern.Clear(); - } - - /// - /// Get the current call pattern. - /// - public static IList GetCallPattern() - { - return CollectionUtil.NewList(callPattern); - } - - /// - /// Adds the call to the internal call pattern. - /// - public static void AddCall(string methodName, params object[] args) - { - callPattern.Add(new Call(methodName, args)); - } - } - - public class MockAllOpsConnector : MockConnector, CreateOp, - DeleteOp, UpdateOp, SearchOp, UpdateAttributeValuesOp, AuthenticateOp, - ResolveUsernameOp, TestOp, ScriptOnConnectorOp, ScriptOnResourceOp - { - - public object RunScriptOnConnector(ScriptContext request, - OperationOptions options) - { - Assert.IsNotNull(request); - Assert.IsNotNull(options); - AddCall("RunScriptOnConnector", request, options); - return null; - } - - public object RunScriptOnResource(ScriptContext request, - OperationOptions options) - { - Assert.IsNotNull(request); - Assert.IsNotNull(options); - AddCall("RunScriptOnResource", request, options); - return null; - } - - public Uid Create(ObjectClass oclass, ICollection attrs, - OperationOptions options) - { - Assert.IsNotNull(attrs); - AddCall("Create", attrs); - return null; - } - - public void Delete(ObjectClass objClass, Uid uid, - OperationOptions options) - { - Assert.IsNotNull(uid); - Assert.IsNotNull(objClass); - AddCall("Delete", objClass, uid); - } - - public Uid Update(ObjectClass objclass, Uid uid, ICollection attrs, - OperationOptions options) - { - Assert.IsNotNull(objclass); - Assert.IsNotNull(attrs); - AddCall("Update", objclass, attrs); - return null; - } - - public Uid AddAttributeValues(ObjectClass objclass, Uid uid, - ICollection valuesToAdd, OperationOptions options) - { - AddCall("AddAttributeValues", objclass, valuesToAdd); - return null; - } - - public Uid RemoveAttributeValues(ObjectClass objclass, Uid uid, - ICollection valuesToRemove, OperationOptions options) - { - AddCall("RemoveAttributeValues", objclass, valuesToRemove); - return null; - } - - public FilterTranslator CreateFilterTranslator(ObjectClass oclass, - OperationOptions options) - { - Assert.IsNotNull(oclass); - Assert.IsNotNull(options); - AddCall("CreateFilterTranslator", oclass, options); - // no translation - ok since this is just for tests - return new MockFilterTranslator(); - } - - public void ExecuteQuery(ObjectClass oclass, string query, - ResultsHandler handler, OperationOptions options) - { - Assert.IsNotNull(oclass); - Assert.IsNotNull(handler); - Assert.IsNotNull(options); - AddCall("ExecuteQuery", oclass, query, handler, options); - } - - public Uid Authenticate(ObjectClass objectClass, string username, GuardedString password, - OperationOptions options) - { - Assert.IsNotNull(username); - Assert.IsNotNull(password); - AddCall("Authenticate", username, password); - return null; - } - - public Uid ResolveUsername(ObjectClass objectClass, string username, OperationOptions options) - { - Assert.IsNotNull(username); - AddCall("ResolveUsername", username); - return null; - } - - public void Test() - { - AddCall("Test"); - } - } - - public class MockUpdateConnector : Connector, UpdateOp, SearchOp - { - - private Configuration _cfg; - - public void Dispose() - { - // nothing to do this is a mock connector.. - } - - public void Init(Configuration cfg) - { - _cfg = cfg; - } - - public Configuration GetConfiguration() - { - return _cfg; - } - - private static IList objects = new List(); - - static MockUpdateConnector() - { - ConnectorObjectBuilder bld = new ConnectorObjectBuilder(); - for (int i = 0; i < 100; i++) - { - bld.SetUid(Convert.ToString(i)); - bld.SetName(Convert.ToString(i)); - objects.Add(bld.Build()); - } - } - - /// - /// This will do a basic replace. - /// - /// - /// - /// - public Uid Update(ObjectClass objclass, Uid uid, ICollection attrs, OperationOptions options) - { - string val = ConnectorAttributeUtil.GetAsStringValue(uid); - int idx = Convert.ToInt32(val); - //.Get out the object.. - ConnectorObject baseObject = objects[idx]; - ConnectorObjectBuilder bld = new ConnectorObjectBuilder(); - bld.Add(baseObject); - bld.AddAttributes(attrs); - ConnectorObject obj = bld.Build(); - objects[idx] = obj; - return obj.Uid; - } - - public FilterTranslator CreateFilterTranslator(ObjectClass oclass, OperationOptions options) - { - //no translation - ok since this is just for tests - return new MockFilterTranslator(); - } - - /// - /// Simply return everything don't bother optimizing. - /// - /// - /// - public void ExecuteQuery(ObjectClass oclass, string query, ResultsHandler handler, OperationOptions options) - { - foreach (ConnectorObject obj in objects) - { - if (!handler(obj)) - { - break; - } - } - } - } - - class MockFilterTranslator : AbstractFilterTranslator - { - } - - public class MockConfiguration : AbstractConfiguration - { - - private readonly bool fail; - - public MockConfiguration() - { - } - - /// - /// Determines if this configuration will fail validation. - /// - public MockConfiguration(bool failvalidation) - { - this.fail = failvalidation; - } - - public bool Fail - { - get; - set; - } - - public override void Validate() - { - if (fail) - { - throw new ConfigurationException(); - } - } - - } -} \ No newline at end of file diff --git a/FrameworkTests/ObjectClassUtilTests.cs b/FrameworkTests/ObjectClassUtilTests.cs deleted file mode 100755 index b74f2ed..0000000 --- a/FrameworkTests/ObjectClassUtilTests.cs +++ /dev/null @@ -1,45 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 NUnit.Framework; -using Org.IdentityConnectors.Framework.Common.Objects; - -namespace FrameworkTests -{ - [TestFixture] - public class ObjectClassUtilTests - { - - [Test] - public void TestIsSpecial() - { - Assert.IsTrue(ObjectClassUtil.IsSpecial(ObjectClass.ACCOUNT)); - Assert.IsFalse(ObjectClassUtil.IsSpecial(new ObjectClass("o"))); - } - - [Test] - public void TestNamesEqual() - { - Assert.IsTrue(ObjectClassUtil.NamesEqual("ACCOUNT", "account")); - } - } -} diff --git a/FrameworkTests/ObjectNormalizerFacadeTests.cs b/FrameworkTests/ObjectNormalizerFacadeTests.cs deleted file mode 100644 index f9a75d1..0000000 --- a/FrameworkTests/ObjectNormalizerFacadeTests.cs +++ /dev/null @@ -1,251 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 NUnit.Framework; -using NUnit.Framework.SyntaxHelpers; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Common.Objects.Filters; -using Org.IdentityConnectors.Framework.Common.Serializer; -using Org.IdentityConnectors.Framework.Spi; -using Org.IdentityConnectors.Framework.Impl.Api.Local.Operations; -namespace FrameworkTests -{ - [TestFixture] - public class ObjectNormalizerFacadeTests - { - public class MyAttributeNormalizer : AttributeNormalizer - { - public ConnectorAttribute NormalizeAttribute(ObjectClass oclass, ConnectorAttribute attribute) - { - if (attribute.Is("foo")) - { - String val = ConnectorAttributeUtil.GetStringValue(attribute); - return ConnectorAttributeBuilder.Build("foo", val.Trim()); - } - else - { - return attribute; - } - } - } - - private ConnectorAttribute CreateTestAttribute() - { - return ConnectorAttributeBuilder.Build("foo", " bar "); - } - - private ConnectorAttribute CreateNormalizedTestAttribute() - { - return ConnectorAttributeBuilder.Build("foo", "bar"); - } - - private ObjectNormalizerFacade CreateTestNormalizer() - { - ObjectNormalizerFacade facade = new - ObjectNormalizerFacade(ObjectClass.ACCOUNT, - new MyAttributeNormalizer()); - return facade; - } - - private void AssertNormalizedFilter(Filter expectedNormalizedFilter, - Filter filter) - { - ObjectNormalizerFacade facade = - CreateTestNormalizer(); - filter = facade.NormalizeFilter(filter); - String expectedXml = SerializerUtil.SerializeXmlObject(expectedNormalizedFilter, false); - String actualXml = SerializerUtil.SerializeXmlObject(filter, false); - Assert.AreEqual(expectedXml, actualXml); - } - - - - [Test] - public void TestEndsWith() - { - Filter expected = - FilterBuilder.EndsWith(CreateNormalizedTestAttribute()); - Filter filter = - FilterBuilder.EndsWith(CreateTestAttribute()); - AssertNormalizedFilter(expected, filter); - } - [Test] - public void TestStartsWith() - { - Filter expected = - FilterBuilder.StartsWith(CreateNormalizedTestAttribute()); - Filter filter = - FilterBuilder.StartsWith(CreateTestAttribute()); - AssertNormalizedFilter(expected, filter); - } - [Test] - public void TestContains() - { - Filter expected = - FilterBuilder.Contains(CreateNormalizedTestAttribute()); - Filter filter = - FilterBuilder.Contains(CreateTestAttribute()); - AssertNormalizedFilter(expected, filter); - } - [Test] - public void TestEqualTo() - { - Filter expected = - FilterBuilder.EqualTo(CreateNormalizedTestAttribute()); - Filter filter = - FilterBuilder.EqualTo(CreateTestAttribute()); - AssertNormalizedFilter(expected, filter); - } - [Test] - public void TestGreaterThanOrEqualTo() - { - Filter expected = - FilterBuilder.GreaterThanOrEqualTo(CreateNormalizedTestAttribute()); - Filter filter = - FilterBuilder.GreaterThanOrEqualTo(CreateTestAttribute()); - AssertNormalizedFilter(expected, filter); - } - [Test] - public void TestLessThanOrEqualTo() - { - Filter expected = - FilterBuilder.LessThanOrEqualTo(CreateNormalizedTestAttribute()); - Filter filter = - FilterBuilder.LessThanOrEqualTo(CreateTestAttribute()); - AssertNormalizedFilter(expected, filter); - } - [Test] - public void TestLessThan() - { - Filter expected = - FilterBuilder.LessThan(CreateNormalizedTestAttribute()); - Filter filter = - FilterBuilder.LessThan(CreateTestAttribute()); - AssertNormalizedFilter(expected, filter); - } - [Test] - public void TestGreaterThan() - { - Filter expected = - FilterBuilder.GreaterThan(CreateNormalizedTestAttribute()); - Filter filter = - FilterBuilder.GreaterThan(CreateTestAttribute()); - AssertNormalizedFilter(expected, filter); - } - [Test] - public void TestAnd() - { - Filter expected = - FilterBuilder.And(FilterBuilder.Contains(CreateNormalizedTestAttribute()), - FilterBuilder.Contains(CreateNormalizedTestAttribute())); - Filter filter = - FilterBuilder.And(FilterBuilder.Contains(CreateTestAttribute()), - FilterBuilder.Contains(CreateTestAttribute())); - AssertNormalizedFilter(expected, filter); - } - [Test] - public void TestOr() - { - Filter expected = - FilterBuilder.Or(FilterBuilder.Contains(CreateNormalizedTestAttribute()), - FilterBuilder.Contains(CreateNormalizedTestAttribute())); - Filter filter = - FilterBuilder.Or(FilterBuilder.Contains(CreateTestAttribute()), - FilterBuilder.Contains(CreateTestAttribute())); - AssertNormalizedFilter(expected, filter); - } - [Test] - public void TestNot() - { - Filter expected = - FilterBuilder.Not(FilterBuilder.Contains(CreateNormalizedTestAttribute())); - Filter filter = - FilterBuilder.Not(FilterBuilder.Contains(CreateTestAttribute())); - AssertNormalizedFilter(expected, filter); - } - [Test] - public void TestContainsAllValues() - { - Filter expected = - FilterBuilder.ContainsAllValues(CreateNormalizedTestAttribute()); - Filter filter = - FilterBuilder.ContainsAllValues(CreateTestAttribute()); - AssertNormalizedFilter(expected, filter); - } - [Test] - public void TestConnectorObject() - { - ConnectorObjectBuilder builder = - new ConnectorObjectBuilder(); - builder.SetName("myname"); - builder.SetUid("myuid"); - builder.AddAttribute(CreateTestAttribute()); - ConnectorObject v1 = builder.Build(); - ConnectorObject v2 = CreateTestNormalizer().NormalizeObject(v1); - builder = - new ConnectorObjectBuilder(); - builder.SetName("myname"); - builder.SetUid("myuid"); - builder.AddAttribute(CreateNormalizedTestAttribute()); - ConnectorObject expected = builder.Build(); - Assert.AreEqual(expected, v2); - Assert.IsFalse(expected.Equals(v1)); - } - - [Test] - public void TestSyncDelta() - { - ConnectorObjectBuilder objbuilder = - new ConnectorObjectBuilder(); - objbuilder.SetName("myname"); - objbuilder.SetUid("myuid"); - objbuilder.AddAttribute(CreateTestAttribute()); - ConnectorObject obj = objbuilder.Build(); - - SyncDeltaBuilder builder = - new SyncDeltaBuilder(); - builder.DeltaType = (SyncDeltaType.DELETE); - builder.Token = (new SyncToken("mytoken")); - builder.Uid = (new Uid("myuid")); - builder.Object = (obj); - SyncDelta v1 = builder.Build(); - SyncDelta v2 = CreateTestNormalizer().NormalizeSyncDelta(v1); - builder = - new SyncDeltaBuilder(); - builder.DeltaType = (SyncDeltaType.DELETE); - builder.Token = (new SyncToken("mytoken")); - builder.Uid = (new Uid("myuid")); - objbuilder = - new ConnectorObjectBuilder(); - objbuilder.SetName("myname"); - objbuilder.SetUid("myuid"); - objbuilder.AddAttribute(CreateNormalizedTestAttribute()); - builder.Object = objbuilder.Build(); - SyncDelta expected = builder.Build(); - Assert.AreEqual(expected, v2); - Assert.IsFalse(expected.Equals(v1)); - - } - - } -} \ No newline at end of file diff --git a/FrameworkTests/ObjectPoolTests.cs b/FrameworkTests/ObjectPoolTests.cs deleted file mode 100644 index a400305..0000000 --- a/FrameworkTests/ObjectPoolTests.cs +++ /dev/null @@ -1,284 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Threading; -using NUnit.Framework; -using NUnit.Framework.SyntaxHelpers; - -using Org.IdentityConnectors.Common.Pooling; -using Org.IdentityConnectors.Framework.Common.Exceptions; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Spi; -using Org.IdentityConnectors.Framework.Impl.Api.Local; - -namespace FrameworkTests -{ - [TestFixture] - public class ObjectPoolTests - { - private class MyTestConnection - { - private bool _isGood = true; - - public void Test() - { - if (!_isGood) - { - throw new ConnectorException("Connection is bad"); - } - } - - public void Dispose() - { - _isGood = false; - } - - public bool IsGood - { - get - { - return _isGood; - } - } - } - - private class MyTestConnectionFactory : ObjectPoolHandler - { - - private bool _createBadConnection = false; - private int _totalCreatedConnections = 0; - - public MyTestConnection NewObject() - { - _totalCreatedConnections++; - MyTestConnection rv = new MyTestConnection(); - if (_createBadConnection) - { - rv.Dispose(); - } - return rv; - } - public void TestObject(MyTestConnection obj) - { - obj.Test(); - } - public void DisposeObject(MyTestConnection obj) - { - obj.Dispose(); - } - - public int TotalCreatedConnections - { - get - { - return _totalCreatedConnections; - } - } - - public bool CreateBadConnection - { - set - { - _createBadConnection = value; - } - } - } - - private class MyTestThread - { - private readonly ObjectPool _pool; - private readonly int _numIterations; - private Exception _exception; - private Thread _thisThread; - public MyTestThread(ObjectPool pool, - int numIterations) - { - _pool = pool; - _numIterations = numIterations; - _thisThread = new Thread(Run); - } - - public void Start() - { - _thisThread.Start(); - } - - public void Run() - { - try - { - for (int i = 0; i < _numIterations; i++) - { - MyTestConnection con = - _pool.BorrowObject(); - Thread.Sleep(300); - _pool.ReturnObject(con); - } - } - catch (Exception e) - { - _exception = e; - } - } - public void Shutdown() - { - _thisThread.Join(); - if (_exception != null) - { - throw _exception; - } - } - - } - - [Test] - public void TestWithManyThreads() - { - int NUM_ITERATIONS = 10; - int NUM_THREADS = 10; - int MAX_CONNECTIONS = NUM_THREADS - 3; //make sure we get some waiting - ObjectPoolConfiguration config = new ObjectPoolConfiguration(); - config.MaxObjects = (MAX_CONNECTIONS); - config.MaxIdle = (MAX_CONNECTIONS); - config.MinIdle = (MAX_CONNECTIONS); - config.MinEvictableIdleTimeMillis = (60 * 1000); - config.MaxWait = (60 * 1000); - MyTestConnectionFactory fact = new MyTestConnectionFactory(); - - ObjectPool pool = new ObjectPool(fact, config); - - MyTestThread[] threads = new MyTestThread[NUM_THREADS]; - for (int i = 0; i < threads.Length; i++) - { - threads[i] = new MyTestThread(pool, NUM_ITERATIONS); - threads[i].Start(); - } - - foreach (MyTestThread thread in threads) - { - thread.Shutdown(); - } - - //these should be the same since we never - //should have disposed anything - Assert.AreEqual(MAX_CONNECTIONS, fact.TotalCreatedConnections); - ObjectPool.Statistics stats = pool.GetStatistics(); - Assert.AreEqual(0, stats.NumActive); - Assert.AreEqual(MAX_CONNECTIONS, stats.NumIdle); - - pool.Shutdown(); - stats = pool.GetStatistics(); - Assert.AreEqual(0, stats.NumActive); - Assert.AreEqual(0, stats.NumIdle); - - } - - [Test] - public void TestBadConnection() - { - int MAX_CONNECTIONS = 3; - ObjectPoolConfiguration config = new ObjectPoolConfiguration(); - config.MaxObjects = (MAX_CONNECTIONS); - config.MaxIdle = (MAX_CONNECTIONS); - config.MinIdle = (MAX_CONNECTIONS); - config.MinEvictableIdleTimeMillis = (60 * 1000); - config.MaxWait = (60 * 1000); - MyTestConnectionFactory fact = new MyTestConnectionFactory(); - - ObjectPool pool = new ObjectPool(fact, config); - - //borrow first connection and return - MyTestConnection conn = pool.BorrowObject(); - Assert.AreEqual(1, fact.TotalCreatedConnections); - pool.ReturnObject(conn); - Assert.AreEqual(1, fact.TotalCreatedConnections); - - //re-borrow same connection and return - conn = pool.BorrowObject(); - Assert.AreEqual(1, fact.TotalCreatedConnections); - pool.ReturnObject(conn); - Assert.AreEqual(1, fact.TotalCreatedConnections); - - //dispose and make sure we get a new connection - conn.Dispose(); - conn = pool.BorrowObject(); - Assert.AreEqual(2, fact.TotalCreatedConnections); - pool.ReturnObject(conn); - Assert.AreEqual(2, fact.TotalCreatedConnections); - } - - [Test] - public void TestIdleCleanup() - { - ObjectPoolConfiguration config = new ObjectPoolConfiguration(); - config.MaxObjects = (3); - config.MaxIdle = (2); - config.MinIdle = (1); - config.MinEvictableIdleTimeMillis = (3000); - config.MaxWait = (60 * 1000); - MyTestConnectionFactory fact = new MyTestConnectionFactory(); - - ObjectPool pool = new ObjectPool(fact, config); - - MyTestConnection conn1 = (MyTestConnection)pool.BorrowObject(); - MyTestConnection conn2 = (MyTestConnection)pool.BorrowObject(); - MyTestConnection conn3 = (MyTestConnection)pool.BorrowObject(); - - Assert.AreEqual(3, fact.TotalCreatedConnections); - pool.ReturnObject(conn1); - Assert.AreEqual(1, pool.GetStatistics().NumIdle); - pool.ReturnObject(conn2); - Assert.AreEqual(2, pool.GetStatistics().NumIdle); - pool.ReturnObject(conn3); - Assert.AreEqual(2, pool.GetStatistics().NumIdle); - Assert.AreEqual(false, conn1.IsGood); - Assert.AreEqual(true, conn2.IsGood); - Assert.AreEqual(true, conn3.IsGood); - Thread.Sleep(((int)(config.MinEvictableIdleTimeMillis + 1000))); - MyTestConnection conn4 = (MyTestConnection)pool.BorrowObject(); - Assert.AreSame(conn3, conn4); - Assert.AreEqual(false, conn1.IsGood); - Assert.AreEqual(false, conn2.IsGood); - Assert.AreEqual(true, conn3.IsGood); - Assert.AreEqual(true, conn4.IsGood); - } - - [Test] - public void TestCreateBadConnection() - { - MyTestConnectionFactory fact = new MyTestConnectionFactory(); - fact.CreateBadConnection = (true); - - ObjectPool pool = new ObjectPool(fact, new ObjectPoolConfiguration()); - try - { - pool.BorrowObject(); - Assert.Fail("expected exception"); - } - catch (ConnectorException e) - { - Assert.AreEqual("Connection is bad", e.Message); - } - } - } -} diff --git a/FrameworkTests/ObjectSerializationTests.cs b/FrameworkTests/ObjectSerializationTests.cs deleted file mode 100644 index 02746c1..0000000 --- a/FrameworkTests/ObjectSerializationTests.cs +++ /dev/null @@ -1,1248 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.IO; -using System.Text; -using NUnit.Framework; -using NUnit.Framework.SyntaxHelpers; -using System.Collections.Generic; -using System.Globalization; -using System.Security; -using System.Linq; -using System.Xml; -using Org.IdentityConnectors.Framework.Impl.Serializer.Binary; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Common.Pooling; -using Org.IdentityConnectors.Common.Security; -using Org.IdentityConnectors.Framework.Api; -using Org.IdentityConnectors.Framework.Api.Operations; -using Org.IdentityConnectors.Framework.Common; -using Org.IdentityConnectors.Framework.Common.Exceptions; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Common.Objects.Filters; -using Org.IdentityConnectors.Framework.Common.Serializer; -using Org.IdentityConnectors.Framework.Impl.Api; -using Org.IdentityConnectors.Framework.Impl.Api.Remote; -using Org.IdentityConnectors.Framework.Impl.Api.Remote.Messages; -using Org.IdentityConnectors.Framework.Impl.Serializer.Xml; -namespace FrameworkTests -{ - [TestFixture] - public class ObjectSerializationTests - { - [Test] - public void TestBoolean() - { - bool v1 = true; - bool v2 = (bool)CloneObject(v1); - Assert.AreEqual(v1, v2); - - v1 = false; - v2 = (bool)CloneObject(v1); - Assert.AreEqual(v1, v2); - } - [Test] - public void TestCharacter() - { - char v1 = 'h'; - char v2 = (char)CloneObject(v1); - Assert.AreEqual(v1, v2); - } - [Test] - public void TestInteger() - { - int v1 = 12345; - int v2 = (int)CloneObject(v1); - Assert.AreEqual(v1, v2); - - v1 = Int32.MinValue; - v2 = (int)CloneObject(v1); - Assert.AreEqual(v1, v2); - - v1 = Int32.MaxValue; - v2 = (int)CloneObject(v1); - Assert.AreEqual(v1, v2); - - v1 = -1; - v2 = (int)CloneObject(v1); - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestLong() - { - long v1 = 12345; - long v2 = (long)CloneObject(v1); - Assert.AreEqual(v1, v2); - - v1 = Int64.MinValue; - v2 = (long)CloneObject(v1); - Assert.AreEqual(v1, v2); - - v1 = Int64.MaxValue; - v2 = (long)CloneObject(v1); - Assert.AreEqual(v1, v2); - - v1 = -1; - v2 = (long)CloneObject(v1); - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestFloat() - { - float v1 = 1.1F; - float v2 = (float)CloneObject(v1); - Assert.IsTrue(!Object.ReferenceEquals(v1, v2)); - Assert.AreEqual(v1, v2); - - v1 = Single.Epsilon; - v2 = (float)CloneObject(v1); - Assert.AreEqual(v1, v2); - - v1 = Single.NaN; - v2 = (float)CloneObject(v1); - Assert.AreEqual(v1, v2); - - v1 = Single.NegativeInfinity; - v2 = (float)CloneObject(v1); - Assert.AreEqual(v1, v2); - - v1 = Single.PositiveInfinity; - v2 = (float)CloneObject(v1); - Assert.AreEqual(v1, v2); - - v1 = Single.MinValue; - v2 = (float)CloneObject(v1); - Assert.AreEqual(v1, v2); - - v1 = Single.MaxValue; - v2 = (float)CloneObject(v1); - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestDouble() - { - double v1 = 1.1; - double v2 = (double)CloneObject(v1); - Assert.IsTrue(!Object.ReferenceEquals(v1, v2)); - Assert.AreEqual(v1, v2); - - v1 = Double.Epsilon; - v2 = (double)CloneObject(v1); - Assert.AreEqual(v1, v2); - - v1 = Double.NaN; - v2 = (double)CloneObject(v1); - Assert.AreEqual(v1, v2); - - v1 = Double.NegativeInfinity; - v2 = (double)CloneObject(v1); - Assert.AreEqual(v1, v2); - - v1 = Double.PositiveInfinity; - v2 = (double)CloneObject(v1); - Assert.AreEqual(v1, v2); - - v1 = Double.MaxValue; - v2 = (double)CloneObject(v1); - Assert.AreEqual(v1, v2); - - v1 = Double.MinValue; - v2 = (double)CloneObject(v1); - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestString() - { - string v1 = "abcd"; - string v2 = (string)CloneObject(v1); - Assert.IsTrue(!Object.ReferenceEquals(v1, v2)); - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestURI() - { - Uri v1 = new Uri("mailto:java-net@java.sun.com"); - Uri v2 = (Uri)CloneObject(v1); - Assert.IsTrue(!Object.ReferenceEquals(v1, v2)); - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestFile() - { - FileName v1 = new FileName("c:/foo.txt"); - FileName v2 = (FileName)CloneObject(v1); - Assert.IsTrue(!Object.ReferenceEquals(v1, v2)); - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestBigInteger() - { - BigInteger v1 = new BigInteger("983423442347324324324"); - BigInteger v2 = (BigInteger)CloneObject(v1); - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestBigDecimal() - { - BigDecimal v1 = new BigDecimal(new BigInteger("9847324324324"), 45); - BigDecimal v2 = (BigDecimal)CloneObject(v1); - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestByteArray() - { - byte[] v1 = { 1, 2, 3 }; - byte[] v2 = (byte[])CloneObject(v1); - Assert.AreEqual(3, v2.Length); - Assert.AreEqual(1, v2[0]); - Assert.AreEqual(2, v2[1]); - Assert.AreEqual(3, v2[2]); - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestClasses() - { - Assert.AreEqual(typeof(bool), - CloneObject(typeof(bool))); - Assert.AreEqual(typeof(bool?), - CloneObject(typeof(bool?))); - Assert.AreEqual(typeof(bool[][]), - CloneObject(typeof(bool[][]))); - Assert.AreEqual(typeof(bool?[][]), - CloneObject(typeof(bool?[][]))); - Assert.AreEqual(typeof(char), - CloneObject(typeof(char))); - Assert.AreEqual(typeof(char?), - CloneObject(typeof(char?))); - //if this fails, we have added a new type and we need to add - //a serializer for it - Assert.IsTrue( - CollectionUtil.SetsEqual( - CollectionUtil.NewSet(FrameworkUtil.GetAllSupportedConfigTypes()), - (ICollection)CloneObject(FrameworkUtil.GetAllSupportedConfigTypes()))); - //if this fails, we have added a new type and we need to add - //a serializer for it - Assert.IsTrue( - CollectionUtil.SetsEqual( - CollectionUtil.NewSet(FrameworkUtil.GetAllSupportedAttributeTypes()), - (ICollection)CloneObject(FrameworkUtil.GetAllSupportedAttributeTypes()))); - ICollection apiOperations = - new HashSet(); - foreach (SafeType op in FrameworkUtil.AllAPIOperations()) - { - apiOperations.Add(op.RawType); - } - //if this fails, need to add to the OperationMappings class - Assert.IsTrue( - CollectionUtil.SetsEqual( - CollectionUtil.NewSet(apiOperations), - (ICollection)CloneObject(apiOperations))); - - } - - [Test] - public void TestArrays() - { - int[] v1 = { 1, 2, 3 }; - int[] v2 = (int[])CloneObject(v1); - Assert.AreEqual(3, v2.Length); - Assert.AreEqual(1, v2[0]); - Assert.AreEqual(2, v2[1]); - Assert.AreEqual(3, v2[2]); - } - - - [Test] - public void TestObjectArrays() - { - object[] v1 = { "1", "2", "3" }; - object[] v2 = (object[])CloneObject(v1); - Assert.AreEqual(3, v2.Length); - Assert.AreEqual("1", v2[0]); - Assert.AreEqual("2", v2[1]); - Assert.AreEqual("3", v2[2]); - } - - [Test] - public void TestDictionary() - { - IDictionary map = new Dictionary(); - map["key1"] = "val1"; - map["key2"] = "val2"; - IDictionary map2 = (IDictionary)CloneObject(map); - Assert.AreEqual("val1", map["key1"]); - Assert.AreEqual("val2", map["key2"]); - - IDictionary map3 = new Dictionary(); - map3["key1"] = "val1"; - map3["key2"] = "val2"; - IDictionary map4 = (IDictionary)CloneObject(map3); - Assert.AreEqual("val1", map4["key1"]); - Assert.AreEqual("val2", map4["key2"]); - } - [Test] - public void TestCaseInsensitiveMap() - { - HashSet set = new HashSet(); - set.Add(ConnectorAttributeBuilder.Build("foo1")); - set.Add(ConnectorAttributeBuilder.Build("foo2")); - IDictionary map = ConnectorAttributeUtil.ToMap(set); - Assert.IsTrue(map.ContainsKey("Foo1")); - Assert.IsTrue(map.ContainsKey("Foo2")); - IDictionary map2 = (IDictionary)CloneObject(map); - Assert.IsTrue(map2.ContainsKey("Foo1")); - Assert.IsTrue(map2.ContainsKey("Foo2")); - } - - [Test] - public void TestList() - { - IList v1 = new List(); - v1.Add("val1"); - v1.Add("val2"); - IList v2 = (IList)CloneObject(v1); - Assert.AreEqual(2, v2.Count); - Assert.AreEqual("val1", v2[0]); - Assert.AreEqual("val2", v2[1]); - - IList v3 = new List(); - v3.Add("val1"); - v3.Add("val2"); - - IList v4 = (IList)CloneObject(v3); - Assert.AreEqual(2, v4.Count); - Assert.AreEqual("val1", v4[0]); - Assert.AreEqual("val2", v4[1]); - } - - [Test] - public void TestSet() - { - //underneath the covers, this creates an - //ICollection - we need to test that ICollection - //becomes a Set - ICollection v1 = - CollectionUtil.NewReadOnlySet("val1", "val2"); - HashSet v2 = (HashSet)CloneObject(v1); - Assert.AreEqual(2, v2.Count); - Assert.IsTrue(v2.Contains("val1")); - Assert.IsTrue(v2.Contains("val2")); - - HashSet v3 = new HashSet(); - v3.Add("val1"); - v3.Add("val2"); - - HashSet v4 = (HashSet)CloneObject(v3); - Assert.AreEqual(2, v4.Count); - Assert.IsTrue(v4.Contains("val1")); - Assert.IsTrue(v4.Contains("val2")); - } - - [Test] - public void TestCaseInsensitiveSet() - { - ICollection v1 = CollectionUtil.NewCaseInsensitiveSet(); - v1.Add("foo"); - v1.Add("foo2"); - ICollection v2 = (ICollection)CloneObject(v1); - Assert.IsTrue(v2.Contains("Foo")); - Assert.IsTrue(v2.Contains("Foo2")); - } - - [Test] - public void TestCultureInfo() - { - //use this one since it uses all 3 fields of locale - CultureInfo v1 = new CultureInfo("nn-NO"); - CultureInfo v2 = (CultureInfo)CloneObject(v1); - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestObjectPoolConfiguration() - { - ObjectPoolConfiguration v1 = new ObjectPoolConfiguration(); - v1.MaxObjects = 1; - v1.MaxIdle = 2; - v1.MaxWait = 3; - v1.MinEvictableIdleTimeMillis = 4; - v1.MinIdle = 5; - ObjectPoolConfiguration v2 = - (ObjectPoolConfiguration)CloneObject(v1); - Assert.IsTrue(!Object.ReferenceEquals(v1, v2)); - - Assert.AreEqual(v1, v2); - - Assert.AreEqual(1, v2.MaxObjects); - Assert.AreEqual(2, v2.MaxIdle); - Assert.AreEqual(3, v2.MaxWait); - Assert.AreEqual(4, v2.MinEvictableIdleTimeMillis); - Assert.AreEqual(5, v2.MinIdle); - } - [Test] - public void TestConfigurationProperty() - { - ConfigurationPropertyImpl v1 = new ConfigurationPropertyImpl(); - v1.Order = (1); - v1.IsConfidential = (true); - v1.IsRequired = true; - v1.Name = ("foo"); - v1.HelpMessageKey = ("help key"); - v1.DisplayMessageKey = ("display key"); - v1.Value = ("bar"); - v1.ValueType = (typeof(string)); - v1.Operations = FrameworkUtil.AllAPIOperations(); - - ConfigurationPropertyImpl v2 = (ConfigurationPropertyImpl) - CloneObject(v1); - Assert.AreEqual(1, v2.Order); - Assert.IsTrue(v2.IsConfidential); - Assert.IsTrue(v2.IsRequired); - Assert.AreEqual("foo", v2.Name); - Assert.AreEqual("help key", v2.HelpMessageKey); - Assert.AreEqual("display key", v2.DisplayMessageKey); - Assert.AreEqual("bar", v2.Value); - Assert.AreEqual(typeof(string), v2.ValueType); - Assert.IsTrue(CollectionUtil.Equals( - FrameworkUtil.AllAPIOperations(), v2.Operations)); - } - - [Test] - public void TestConfigurationProperties() - { - ConfigurationPropertyImpl prop1 = new ConfigurationPropertyImpl(); - prop1.Order = (1); - prop1.IsConfidential = (true); - prop1.Name = ("foo"); - prop1.HelpMessageKey = ("help key"); - prop1.DisplayMessageKey = ("display key"); - prop1.Value = ("bar"); - prop1.ValueType = (typeof(string)); - prop1.Operations = null; - - ConfigurationPropertiesImpl v1 = new ConfigurationPropertiesImpl(); - v1.Properties = (CollectionUtil.NewReadOnlyList(prop1)); - v1.SetPropertyValue("foo", "bar"); - - ConfigurationPropertiesImpl v2 = (ConfigurationPropertiesImpl) - CloneObject(v1); - Assert.AreEqual("bar", v2.GetProperty("foo").Value); - } - - [Test] - public void TestAPIConfiguration() - { - ConfigurationPropertyImpl prop1 = new ConfigurationPropertyImpl(); - prop1.Order = (1); - prop1.IsConfidential = (true); - prop1.Name = ("foo"); - prop1.HelpMessageKey = ("help key"); - prop1.DisplayMessageKey = ("display key"); - prop1.Value = ("bar"); - prop1.ValueType = (typeof(string)); - prop1.Operations = null; - - ConfigurationPropertiesImpl props1 = new ConfigurationPropertiesImpl(); - props1.Properties = (CollectionUtil.NewReadOnlyList(prop1)); - - APIConfigurationImpl v1 = new APIConfigurationImpl(); - v1.ConnectorPoolConfiguration = (new ObjectPoolConfiguration()); - v1.ConfigurationProperties = (props1); - v1.IsConnectorPoolingSupported = (true); - v1.ProducerBufferSize = (200); - v1.SupportedOperations = (FrameworkUtil.AllAPIOperations()); - IDictionary, int> map = - CollectionUtil.NewDictionary, int>(SafeType.Get(), 6); - v1.TimeoutMap = (map); - - APIConfigurationImpl v2 = (APIConfigurationImpl) - CloneObject(v1); - Assert.IsTrue(!Object.ReferenceEquals(v1, v2)); - Assert.IsNotNull(v2.ConnectorPoolConfiguration); - Assert.IsNotNull(v2.ConfigurationProperties); - Assert.AreEqual(v1.ConnectorPoolConfiguration, v2.ConnectorPoolConfiguration); - Assert.AreEqual(v1.ConfigurationProperties, v2.ConfigurationProperties); - Assert.IsTrue(v2.IsConnectorPoolingSupported); - Assert.AreEqual(200, v2.ProducerBufferSize); - Assert.IsTrue(CollectionUtil.SetsEqual( - FrameworkUtil.AllAPIOperations(), - v2.SupportedOperations)); - Assert.AreEqual(map, v2.TimeoutMap); - } - - [Test] - public void TestConnectorMessages() - { - ConnectorMessagesImpl v1 = new ConnectorMessagesImpl(); - IDictionary defaultMap = new Dictionary(); - defaultMap["key1"] = "val1"; - IDictionary> messages = - new Dictionary>(); - messages[new CultureInfo("en")] = defaultMap; - messages[new CultureInfo("")] = defaultMap; - v1.Catalogs = (messages); - - ConnectorMessagesImpl v2 = (ConnectorMessagesImpl) - CloneObject(v1); - Assert.IsTrue( - CollectionUtil.SetsEqual(messages[new CultureInfo("")], - v2.Catalogs[new CultureInfo("")])); - Assert.IsTrue( - CollectionUtil.SetsEqual(messages[new CultureInfo("en")], - v2.Catalogs[new CultureInfo("en")])); - } - - [Test] - public void TestRemoteConnectorInfo() - { - RemoteConnectorInfoImpl v1 = new RemoteConnectorInfoImpl(); - v1.Messages = (new ConnectorMessagesImpl()); - v1.ConnectorKey = (new ConnectorKey("my bundle", - "my version", - "my connector")); - ConfigurationPropertiesImpl configProperties = new ConfigurationPropertiesImpl(); - configProperties.Properties = (new List()); - APIConfigurationImpl apiImpl = new APIConfigurationImpl(); - apiImpl.ConfigurationProperties = (configProperties); - v1.DefaultAPIConfiguration = (apiImpl); - v1.ConnectorDisplayNameKey = ("mykey"); - - RemoteConnectorInfoImpl v2 = (RemoteConnectorInfoImpl) - CloneObject(v1); - - Assert.IsNotNull(v2.Messages); - Assert.AreEqual("my bundle", v2.ConnectorKey.BundleName); - Assert.AreEqual("my version", v2.ConnectorKey.BundleVersion); - Assert.AreEqual("my connector", v2.ConnectorKey.ConnectorName); - Assert.AreEqual("mykey", v2.ConnectorDisplayNameKey); - Assert.IsNotNull(v2.DefaultAPIConfiguration); - } - - [Test] - public void TestAttribute() - { - ConnectorAttribute v1 = ConnectorAttributeBuilder.Build("foo", "val1", "val2"); - ConnectorAttribute v2 = (ConnectorAttribute)CloneObject(v1); - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestAttributeInfo() - { - - ConnectorAttributeInfoBuilder builder = new ConnectorAttributeInfoBuilder(); - builder.Name = ("foo"); - builder.ValueType = (typeof(String)); - builder.Required = (true); - builder.Readable = (true); - builder.Creatable = (true); - builder.Updateable = (true); - builder.MultiValued = (true); - builder.ReturnedByDefault = false; - ConnectorAttributeInfo v1 = builder.Build(); - ConnectorAttributeInfo v2 = (ConnectorAttributeInfo)CloneObject(v1); - Assert.AreEqual(v1, v2); - Assert.AreEqual("foo", v2.Name); - Assert.AreEqual(typeof(String), v2.ValueType); - Assert.IsTrue(v2.IsMultiValued); - Assert.IsTrue(v2.IsReadable); - Assert.IsTrue(v2.IsRequired); - Assert.IsTrue(v2.IsUpdateable); - Assert.IsTrue(v2.IsCreatable); - Assert.IsFalse(v2.IsReturnedByDefault); - - builder.InfoFlags = AllFlags(); - v1 = builder.Build(); - v2 = (ConnectorAttributeInfo)CloneObject(v1); - Assert.AreEqual(v1, v2); - } - - private ConnectorAttributeInfo.Flags AllFlags() - { - ConnectorAttributeInfo.Flags flags = - ConnectorAttributeInfo.Flags.NONE; - foreach (Enum e in Enum.GetValues(typeof(ConnectorAttributeInfo.Flags))) - { - ConnectorAttributeInfo.Flags f = - (ConnectorAttributeInfo.Flags)e; - flags |= f; - } - return flags; - } - - [Test] - public void TestConnectorObject() - { - ConnectorObjectBuilder bld = new ConnectorObjectBuilder(); - bld.SetUid("foo"); - bld.SetName("fooToo"); - - ConnectorObject v1 = bld.Build(); - ConnectorObject v2 = (ConnectorObject)CloneObject(v1); - - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestName() - { - Name v1 = new Name("Test"); - Name v2 = (Name)CloneObject(v1); - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestObjectClass() - { - ObjectClass v1 = new ObjectClass("test"); - ObjectClass v2 = (ObjectClass)CloneObject(v1); - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestObjectClassInfo() - { - ConnectorAttributeInfoBuilder builder = new ConnectorAttributeInfoBuilder(); - builder.Name = ("foo"); - builder.ValueType = (typeof(String)); - builder.Required = (true); - builder.Readable = (true); - builder.Updateable = (true); - builder.MultiValued = (true); - ObjectClassInfoBuilder obld = new ObjectClassInfoBuilder(); - obld.ObjectType = ObjectClass.ACCOUNT_NAME; - obld.IsContainer = true; - obld.AddAttributeInfo(builder.Build()); - ObjectClassInfo v1 = obld.Build(); - ObjectClassInfo v2 = (ObjectClassInfo)CloneObject(v1); - Assert.AreEqual(v1, v2); - Assert.IsTrue(v2.IsContainer); - } - - [Test] - public void TestUid() - { - Uid v1 = new Uid("test"); - Uid v2 = (Uid)CloneObject(v1); - Assert.AreEqual(v1, v2); - } - - [Test] - public void testOperationOptionInfo() - { - OperationOptionInfo v1 = - new OperationOptionInfo("name", typeof(int?)); - OperationOptionInfo v2 = - (OperationOptionInfo)CloneObject(v1); - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestSchema() - { - OperationOptionInfo opInfo = - new OperationOptionInfo("name", typeof(int?)); - ObjectClassInfoBuilder bld = new ObjectClassInfoBuilder(); - bld.ObjectType = ObjectClass.ACCOUNT_NAME; - ObjectClassInfo info = bld.Build(); - ICollection temp = CollectionUtil.NewSet(info); - IDictionary, ICollection> map = - new Dictionary, ICollection>(); - map[SafeType.Get()] = temp; - ICollection temp2 = CollectionUtil.NewSet(opInfo); - IDictionary, ICollection> map2 = - new Dictionary, ICollection>(); - map2[SafeType.Get()] = temp2; - Schema v1 = new Schema(CollectionUtil.NewSet(info), - CollectionUtil.NewSet(opInfo), - map, - map2); - Schema v2 = (Schema)CloneObject(v1); - Assert.AreEqual(v1, v2); - Assert.AreEqual(info, v2.ObjectClassInfo.First()); - Assert.AreEqual(1, v2.SupportedObjectClassesByOperation.Count); - Assert.AreEqual(1, v2.SupportedOptionsByOperation.Count); - Assert.AreEqual(1, v2.OperationOptionInfo.Count); - } - - [Test] - public void TestContainsFilter() - { - ContainsFilter v1 = new ContainsFilter(ConnectorAttributeBuilder.Build("foo", "bar")); - ContainsFilter v2 = (ContainsFilter)CloneObject(v1); - Assert.AreEqual(v1.GetAttribute(), v2.GetAttribute()); - } - - [Test] - public void TestAndFilter() - { - ContainsFilter left1 = new ContainsFilter(ConnectorAttributeBuilder.Build("foo", "bar")); - ContainsFilter right1 = new ContainsFilter(ConnectorAttributeBuilder.Build("foo2", "bar2")); - AndFilter v1 = new AndFilter(left1, right1); - AndFilter v2 = (AndFilter)CloneObject(v1); - ContainsFilter left2 = (ContainsFilter)v2.Left; - ContainsFilter right2 = (ContainsFilter)v2.Right; - Assert.AreEqual(left1.GetAttribute(), left2.GetAttribute()); - Assert.AreEqual(right1.GetAttribute(), right2.GetAttribute()); - } - - [Test] - public void TestEndsWithFilter() - { - EndsWithFilter v1 = new EndsWithFilter(ConnectorAttributeBuilder.Build("foo", "bar")); - EndsWithFilter v2 = (EndsWithFilter)CloneObject(v1); - Assert.AreEqual(v1.GetAttribute(), v2.GetAttribute()); - } - - [Test] - public void TestEqualsFilter() - { - EqualsFilter v1 = new EqualsFilter(ConnectorAttributeBuilder.Build("foo", "bar")); - EqualsFilter v2 = (EqualsFilter)CloneObject(v1); - Assert.AreEqual(v1.GetAttribute(), v2.GetAttribute()); - } - - [Test] - public void TestGreaterThanFilter() - { - GreaterThanFilter v1 = new GreaterThanFilter(ConnectorAttributeBuilder.Build("foo", "bar")); - GreaterThanFilter v2 = (GreaterThanFilter)CloneObject(v1); - Assert.AreEqual(v1.GetAttribute(), v2.GetAttribute()); - } - - [Test] - public void TestGreaterThanOrEqualFilter() - { - GreaterThanOrEqualFilter v1 = new GreaterThanOrEqualFilter(ConnectorAttributeBuilder.Build("foo", "bar")); - GreaterThanOrEqualFilter v2 = (GreaterThanOrEqualFilter)CloneObject(v1); - Assert.AreEqual(v1.GetAttribute(), v2.GetAttribute()); - } - - [Test] - public void TestLessThanFilter() - { - LessThanFilter v1 = new LessThanFilter(ConnectorAttributeBuilder.Build("foo", "bar")); - LessThanFilter v2 = (LessThanFilter)CloneObject(v1); - Assert.AreEqual(v1.GetAttribute(), v2.GetAttribute()); - } - - [Test] - public void TestLessThanOrEqualFilter() - { - LessThanOrEqualFilter v1 = new LessThanOrEqualFilter(ConnectorAttributeBuilder.Build("foo", "bar")); - LessThanOrEqualFilter v2 = (LessThanOrEqualFilter)CloneObject(v1); - Assert.AreEqual(v1.GetAttribute(), v2.GetAttribute()); - } - - [Test] - public void TestNotFilter() - { - ContainsFilter left1 = new ContainsFilter(ConnectorAttributeBuilder.Build("foo", "bar")); - NotFilter v1 = new NotFilter(left1); - NotFilter v2 = (NotFilter)CloneObject(v1); - ContainsFilter left2 = (ContainsFilter)v2.Filter; - Assert.AreEqual(left1.GetAttribute(), left2.GetAttribute()); - } - - [Test] - public void TestOrFilter() - { - ContainsFilter left1 = new ContainsFilter(ConnectorAttributeBuilder.Build("foo", "bar")); - ContainsFilter right1 = new ContainsFilter(ConnectorAttributeBuilder.Build("foo2", "bar2")); - OrFilter v1 = new OrFilter(left1, right1); - OrFilter v2 = (OrFilter)CloneObject(v1); - ContainsFilter left2 = (ContainsFilter)v2.Left; - ContainsFilter right2 = (ContainsFilter)v2.Right; - Assert.AreEqual(left1.GetAttribute(), left2.GetAttribute()); - Assert.AreEqual(right1.GetAttribute(), right2.GetAttribute()); - } - - [Test] - public void TestStartsWithFilter() - { - StartsWithFilter v1 = new StartsWithFilter(ConnectorAttributeBuilder.Build("foo", "bar")); - StartsWithFilter v2 = (StartsWithFilter)CloneObject(v1); - Assert.AreEqual(v1.GetAttribute(), v2.GetAttribute()); - } - - [Test] - public void TestContainsAllValuesFilter() - { - ContainsAllValuesFilter v1 = new ContainsAllValuesFilter(ConnectorAttributeBuilder.Build("foo", "bar", "foo")); - ContainsAllValuesFilter v2 = (ContainsAllValuesFilter)CloneObject(v1); - Assert.AreEqual(v1.GetAttribute(), v2.GetAttribute()); - } - - [Test] - public void TestExceptions() - { - { - AlreadyExistsException v1 = new AlreadyExistsException("ex"); - AlreadyExistsException v2 = (AlreadyExistsException)CloneObject(v1); - Assert.AreEqual("ex", v2.Message); - } - - { - ConfigurationException v1 = new ConfigurationException("ex"); - ConfigurationException v2 = (ConfigurationException)CloneObject(v1); - Assert.AreEqual("ex", v2.Message); - } - - { - ConnectionBrokenException v1 = new ConnectionBrokenException("ex"); - ConnectionBrokenException v2 = (ConnectionBrokenException)CloneObject(v1); - Assert.AreEqual("ex", v2.Message); - } - - { - ConnectionFailedException v1 = new ConnectionFailedException("ex"); - ConnectionFailedException v2 = (ConnectionFailedException)CloneObject(v1); - Assert.AreEqual("ex", v2.Message); - } - - { - ConnectorException v1 = new ConnectorException("ex"); - ConnectorException v2 = (ConnectorException)CloneObject(v1); - Assert.AreEqual("ex", v2.Message); - } - { - ConnectorIOException v1 = new ConnectorIOException("ex"); - ConnectorIOException v2 = (ConnectorIOException)CloneObject(v1); - Assert.AreEqual("ex", v2.Message); - } - { - ConnectorSecurityException v1 = new ConnectorSecurityException("ex"); - ConnectorSecurityException v2 = (ConnectorSecurityException)CloneObject(v1); - Assert.AreEqual("ex", v2.Message); - } - - { - InvalidCredentialException v1 = new InvalidCredentialException("ex"); - InvalidCredentialException v2 = (InvalidCredentialException)CloneObject(v1); - Assert.AreEqual("ex", v2.Message); - } - - { - InvalidPasswordException v1 = new InvalidPasswordException("ex"); - InvalidPasswordException v2 = (InvalidPasswordException)CloneObject(v1); - Assert.AreEqual("ex", v2.Message); - } - - { - PasswordExpiredException v1 = new PasswordExpiredException("ex"); - v1.Uid = (new Uid("myuid")); - PasswordExpiredException v2 = (PasswordExpiredException)CloneObject(v1); - Assert.AreEqual("ex", v2.Message); - Assert.AreEqual("myuid", v2.Uid.GetUidValue()); - } - - { - OperationTimeoutException v1 = new OperationTimeoutException("ex"); - OperationTimeoutException v2 = (OperationTimeoutException)CloneObject(v1); - Assert.AreEqual("ex", v2.Message); - } - - { - PermissionDeniedException v1 = new PermissionDeniedException("ex"); - PermissionDeniedException v2 = (PermissionDeniedException)CloneObject(v1); - Assert.AreEqual("ex", v2.Message); - } - - { - UnknownUidException v1 = new UnknownUidException("ex"); - UnknownUidException v2 = (UnknownUidException)CloneObject(v1); - Assert.AreEqual("ex", v2.Message); - } - - { - ArgumentException v1 = new ArgumentException("my msg"); - ArgumentException v2 = (ArgumentException)CloneObject(v1); - Assert.AreEqual("my msg", v2.Message); - } - - { - ArgumentNullException v1 = new ArgumentNullException(null, "my msg 1"); - ArgumentException v2 = (ArgumentException)CloneObject(v1); - Assert.AreEqual("my msg 1", v2.Message); - } - - { - Exception v1 = new Exception("my msg2"); - Exception v2 = (Exception)CloneObject(v1); - Assert.AreEqual("my msg2", v2.Message); - } - - } - - [Test] - public void TestHelloRequest() - { - HelloRequest v1 = new HelloRequest(); - HelloRequest v2 = (HelloRequest)CloneObject(v1); - Assert.IsNotNull(v2); - } - - [Test] - public void TestHelloResponse() - { - RemoteConnectorInfoImpl info = new RemoteConnectorInfoImpl(); - info.Messages = (new ConnectorMessagesImpl()); - info.ConnectorKey = (new ConnectorKey("my bundle", - "my version", - "my connector")); - ConfigurationPropertiesImpl configProperties = new ConfigurationPropertiesImpl(); - configProperties.Properties = (new List()); - APIConfigurationImpl apiImpl = new APIConfigurationImpl(); - apiImpl.ConfigurationProperties = (configProperties); - info.DefaultAPIConfiguration = (apiImpl); - info.ConnectorDisplayNameKey = ("mykey"); - - Exception ex = new Exception("foo"); - HelloResponse v1 = new HelloResponse(ex, CollectionUtil.NewReadOnlyList(info)); - HelloResponse v2 = (HelloResponse)CloneObject(v1); - Assert.IsNotNull(v2.Exception); - Assert.IsNotNull(v2.ConnectorInfos.First()); - } - - [Test] - public void TestOperationRequest() - { - ConfigurationPropertiesImpl configProperties = new ConfigurationPropertiesImpl(); - configProperties.Properties = (new List()); - APIConfigurationImpl apiImpl = new APIConfigurationImpl(); - apiImpl.ConfigurationProperties = (configProperties); - - IList args = new List(); - args.Add("my arg"); - OperationRequest v1 = new - OperationRequest(new ConnectorKey("my bundle", - "my version", - "my connector"), - apiImpl, - SafeType.Get(), - "mymethodName", - args); - OperationRequest v2 = (OperationRequest)CloneObject(v1); - Assert.AreEqual("my bundle", v2.ConnectorKey.BundleName); - Assert.AreEqual("my version", v2.ConnectorKey.BundleVersion); - Assert.AreEqual("my connector", v2.ConnectorKey.ConnectorName); - Assert.IsNotNull(v2.Configuration); - Assert.AreEqual(SafeType.Get(), v2.Operation); - Assert.AreEqual("mymethodName", v2.OperationMethodName); - Assert.IsTrue( - CollectionUtil.Equals( - args, v2.Arguments)); - } - - [Test] - public void TestOperationResponseEnd() - { - OperationResponseEnd v1 = new OperationResponseEnd(); - OperationResponseEnd v2 = (OperationResponseEnd)CloneObject(v1); - Assert.IsNotNull(v2); - } - [Test] - public void TestOperationResponsePart() - { - Exception ex = new Exception("foo"); - OperationResponsePart v1 = new OperationResponsePart(ex, "bar"); - OperationResponsePart v2 = (OperationResponsePart)CloneObject(v1); - Assert.IsNotNull(v2.Exception); - Assert.AreEqual("bar", v2.Result); - } - - [Test] - public void TestOperationResponsePause() - { - OperationResponsePause v1 = new OperationResponsePause(); - OperationResponsePause v2 = (OperationResponsePause)CloneObject(v1); - Assert.IsNotNull(v2); - } - - [Test] - public void TestOperationRequestMoreData() - { - OperationRequestMoreData v1 = new OperationRequestMoreData(); - OperationRequestMoreData v2 = (OperationRequestMoreData)CloneObject(v1); - Assert.IsNotNull(v2); - } - - [Test] - public void TestOperationRequestStopData() - { - OperationRequestStopData v1 = new OperationRequestStopData(); - OperationRequestStopData v2 = (OperationRequestStopData)CloneObject(v1); - Assert.IsNotNull(v2); - } - - [Test] - public void TestEchoMessage() - { - EchoMessage v1 = new EchoMessage("test", "xml"); - EchoMessage v2 = (EchoMessage)CloneObject(v1); - Assert.AreEqual("test", v2.Object); - Assert.AreEqual("xml", v2.ObjectXml); - } - - [Test] - public void TestOperationOptions() - { - OperationOptionsBuilder builder = new OperationOptionsBuilder(); - builder.SetOption("foo", "bar"); - builder.SetOption("foo2", "bar2"); - OperationOptions v1 = builder.Build(); - OperationOptions v2 = (OperationOptions)CloneObject(v1); - Assert.AreEqual(2, v2.Options.Count); - Assert.AreEqual("bar", v2.Options["foo"]); - Assert.AreEqual("bar2", v2.Options["foo2"]); - } - - [Test] - public void TestScript() - { - ScriptBuilder builder = new ScriptBuilder(); - builder.ScriptLanguage = "language"; - builder.ScriptText = "text"; - Script v1 = builder.Build(); - Script v2 = (Script)CloneObject(v1); - Assert.AreEqual("language", v2.ScriptLanguage); - Assert.AreEqual("text", v2.ScriptText); - } - - [Test] - public void TestScriptContext() - { - ScriptContextBuilder builder = new ScriptContextBuilder(); - builder.ScriptLanguage = ("language"); - builder.ScriptText = ("text"); - builder.AddScriptArgument("foo", "bar"); - builder.AddScriptArgument("foo2", "bar2"); - ScriptContext v1 = builder.Build(); - ScriptContext v2 = (ScriptContext)CloneObject(v1); - Assert.AreEqual(2, v2.ScriptArguments.Count); - Assert.AreEqual("bar", v2.ScriptArguments["foo"]); - Assert.AreEqual("bar2", v2.ScriptArguments["foo2"]); - Assert.AreEqual("language", v2.ScriptLanguage); - Assert.AreEqual("text", v2.ScriptText); - } - [Test] - public void TestSyncDeltaType() - { - SyncDeltaType v1 = SyncDeltaType.DELETE; - SyncDeltaType v2 = (SyncDeltaType)CloneObject(v1); - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestSyncToken() - { - SyncToken v1 = new SyncToken("mytoken"); - SyncToken v2 = (SyncToken)CloneObject(v1); - Assert.AreEqual(v1.Value, v2.Value); - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestSyncDelta() - { - ConnectorObjectBuilder bld = new ConnectorObjectBuilder(); - bld.SetUid("foo"); - bld.SetName("name"); - SyncDeltaBuilder builder = new SyncDeltaBuilder(); - builder.PreviousUid = (new Uid("mypreviousuid")); - builder.Uid = (new Uid("myuid")); - builder.DeltaType = (SyncDeltaType.CREATE_OR_UPDATE); - builder.Token = (new SyncToken("mytoken")); - builder.Object = (bld.Build()); - SyncDelta v1 = builder.Build(); - SyncDelta v2 = (SyncDelta)CloneObject(v1); - Assert.AreEqual(new Uid("mypreviousuid"), v2.PreviousUid); - Assert.AreEqual(new Uid("foo"), v2.Uid); - Assert.AreEqual(new SyncToken("mytoken"), v2.Token); - Assert.AreEqual(SyncDeltaType.CREATE_OR_UPDATE, v2.DeltaType); - Assert.AreEqual(v1, v2); - } - - [Test] - public void TestNull() - { - Object v1 = null; - Object v2 = CloneObject(v1); - Assert.IsNull(v2); - } - - [Test] - public void TestGuardedByteArray() - { - GuardedByteArray v1 = new GuardedByteArray(); - v1.AppendByte(0x00); - v1.AppendByte(0x01); - v1.AppendByte(0x02); - GuardedByteArray v2 = (GuardedByteArray)CloneObject(v1); - Assert.AreEqual(new byte[] { 0x00, 0x01, 0x02 }, DecryptToByteArray(v2)); - } - - [Test] - public void TestGuardedString() - { - GuardedString v1 = new GuardedString(); - v1.AppendChar('f'); - v1.AppendChar('o'); - v1.AppendChar('o'); - v1.AppendChar('b'); - v1.AppendChar('a'); - v1.AppendChar('r'); - GuardedString v2 = (GuardedString)CloneObject(v1); - Assert.AreEqual("foobar", DecryptToString(v2)); - } - - [Test] - public void TestQualifiedUid() - { - QualifiedUid v1 = new QualifiedUid(new ObjectClass("myclass"), - new Uid("myuid")); - QualifiedUid v2 = (QualifiedUid)CloneObject(v1); - Assert.AreEqual(v1, v2); - Assert.AreEqual("myclass", v2.ObjectClass.GetObjectClassValue()); - Assert.AreEqual("myuid", v2.Uid.GetUidValue()); - } - - /// - /// Highly insecure method! Do not do this in production - /// code. - /// - /// - /// This is only for test purposes - /// - private String DecryptToString(GuardedString str) - { - StringBuilder buf = new StringBuilder(); - str.Access( - array => - { - for (int i = 0; i < array.Length; i++) - { - buf.Append(array[i]); - } - }); - return buf.ToString(); - } - - private byte[] DecryptToByteArray(GuardedByteArray bytes) - { - byte[] result = null; - bytes.Access( - array => - { - result = new byte[array.Length]; - for (int i = 0; i < array.Length; i++) - { - result[i] = array[i]; - } - }); - return result; - } - - protected virtual Object CloneObject(Object o) - { - return SerializerUtil.CloneObject(o); - } - } - [TestFixture] - public class XmlSerializationTests : ObjectSerializationTests - { - protected override Object CloneObject(Object o) - { - String xml = SerializerUtil.SerializeXmlObject(o, true); - Console.WriteLine(xml); - o = SerializerUtil.DeserializeXmlObject(xml, true); - - //pass through a list to make sure dtd correctly defines all xml objects - List list = new List(); - list.Add(o); - xml = SerializerUtil.SerializeXmlObject(list, true); - Console.WriteLine(xml); - IList rv = (IList)SerializerUtil.DeserializeXmlObject(xml, true); - return rv[0]; - } - - [Test] - public void TestMultiObject() - { - ObjectSerializerFactory factory = ObjectSerializerFactory.GetInstance(); - StringWriter sw = new StringWriter(); - XmlObjectSerializer ser = factory.NewXmlSerializer(sw, true, true); - ser.WriteObject("foo"); - ser.WriteObject("bar"); - ser.Close(true); - String xml = sw.ToString(); - Console.WriteLine(xml); - IList results = new List(); - factory.DeserializeXmlStream(new StringReader(xml), - o => - { - results.Add(o); - return true; - }, - true); - Assert.AreEqual(2, results.Count); - Assert.AreEqual("foo", results[0]); - Assert.AreEqual("bar", results[1]); - } - - [Test] - public void TestWriter() - { - XmlWriterSettings settings = new XmlWriterSettings(); - settings.Indent = true; - settings.OmitXmlDeclaration = true; - XmlWriter writer = XmlWriter.Create(Console.Out, settings); - - // Write the book element. - writer.WriteStartElement("book"); - writer.WriteEndElement(); - writer.Close(); - // Write the title element. - //writer.WriteStartElement("title"); - //writer.WriteString("Pride And Prejudice<<"); - //writer.WriteEndElement(); - - // Write the close tag for the root element. - //writer.WriteEndElement(); - - // Write the XML and close the writer. - //writer.Close(); - - } - } -} \ No newline at end of file diff --git a/FrameworkTests/Org.IdentityConnectors.TestConnector.FakeConnector/config/config.xml b/FrameworkTests/Org.IdentityConnectors.TestConnector.FakeConnector/config/config.xml deleted file mode 100644 index f2546a2..0000000 --- a/FrameworkTests/Org.IdentityConnectors.TestConnector.FakeConnector/config/config.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/FrameworkTests/Org.IdentityConnectors.TestConnector.FakeConnector/config/myconfig/config.xml b/FrameworkTests/Org.IdentityConnectors.TestConnector.FakeConnector/config/myconfig/config.xml deleted file mode 100644 index 5df51e6..0000000 --- a/FrameworkTests/Org.IdentityConnectors.TestConnector.FakeConnector/config/myconfig/config.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/FrameworkTests/PropertyBagTests.cs b/FrameworkTests/PropertyBagTests.cs deleted file mode 100644 index 1358b25..0000000 --- a/FrameworkTests/PropertyBagTests.cs +++ /dev/null @@ -1,135 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Linq; -using System.Text; -using NUnit.Framework; -using Org.IdentityConnectors.Test.Common; -using Org.IdentityConnectors.Common; - -namespace FrameworkTests -{ - [TestFixture] - public class PropertyBagTests - { - private PropertyBag bag = null; - - [SetUp] - public void SetUp() - { - bag = CreateBag(); - } - - [Test] - public void TestGetProperty() - { - Assert.AreEqual("value1", bag.GetProperty("key1")); - Assert.IsNull(bag.GetProperty("key2")); - - Assert.AreEqual((int?)1, bag.GetProperty("key3")); - Assert.AreEqual((long?)1, bag.GetProperty("key5")); - - // try not existing - try - { - bag.GetProperty("key4"); - Assert.Fail("Get Property must fail for unexisting property"); - } - catch (ArgumentException) - { - } - - // Try cast - try - { - bag.GetProperty("key3"); - Assert.Fail("Get Property with incompatible type must fail on InvalidCastException"); - } - catch (InvalidCastException) - { - } - } - - [Test] - public void TestGetPropertyWithDef() - { - Assert.AreEqual("value1", bag.GetProperty("key1", "def")); - Assert.IsNull(bag.GetProperty("key2", "def")); - Assert.AreEqual("def", bag.GetProperty("key4", "def")); - Assert.IsNull(bag.GetProperty("key4", null)); - } - - [Test] - public void TestGetStringProperty() - { - Assert.AreEqual("value1", bag.GetStringProperty("key1")); - Assert.IsNull(bag.GetStringProperty("key2")); - // Try cast - try - { - bag.GetStringProperty("key3"); - Assert.Fail("Get Property with incompatible type must fail on InvalidCastException"); - } - catch (InvalidCastException) - { - } - - // try not existing - try - { - bag.GetStringProperty("key4"); - Assert.Fail("Get String Property must fail for unexisting property"); - } - catch (ArgumentException) - { - } - } - - [Test] - public void TestToDictionary() - { - var properties = bag.ToDictionary(); - Assert.That(CollectionUtil.DictionariesEqual(properties, CreateDictionary()), - "ToDictionary must return the same properties as it was created with" ); - } - - private static PropertyBag CreateBag() - { - var properties = CreateDictionary(); - return new PropertyBag(properties); - } - - private static Dictionary CreateDictionary() - { - var properties = new Dictionary - { - {"key1", "value1"}, - {"key2", null}, - {"key3", (int?) 1}, - {"key5", (long?) 1} - }; - return properties; - } - } -} diff --git a/FrameworkTests/ProxyTests.cs b/FrameworkTests/ProxyTests.cs deleted file mode 100644 index 1714f54..0000000 --- a/FrameworkTests/ProxyTests.cs +++ /dev/null @@ -1,97 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 NUnit.Framework; -using NUnit.Framework.SyntaxHelpers; -using System.Reflection; -using System.Reflection.Emit; -using Org.IdentityConnectors.Common.Proxy; -using System.Collections.Generic; -using Org.IdentityConnectors.Common; -namespace FrameworkTests -{ - public interface MyTestInterface - { - string TestProperty { get; set; } - - String TestTwoArgs(string val1, string val2); - void TestVoid(IList list); - int TestPrimitive(int arg); - DateTime TestStruct(DateTime arg); - } - - [TestFixture] - public class ProxyTests - { - public class MyHandler : InvocationHandler - { - private string _testProperty; - - public Object Invoke(Object proxy, MethodInfo method, Object[] args) - { - if (method.Name.Equals("TestTwoArgs")) - { - return "" + method.Name + " " + args[0] + " " + args[1]; - } - else if (method.Name.Equals("TestVoid")) - { - IList arg = (IList)args[0]; - arg.Add("my void result"); - return null; - } - else if (method.Name.Equals("get_TestProperty")) - { - return _testProperty; - } - else if (method.Name.Equals("set_TestProperty")) - { - _testProperty = (string)args[0]; - return null; - } - else - { - return args[0]; - } - } - } - - [Test] - public void TestProxy() - { - InvocationHandler handler = new MyHandler(); - - MyTestInterface inter = - (MyTestInterface)Proxy.NewProxyInstance(typeof(MyTestInterface), - handler); - Assert.AreEqual("TestTwoArgs foo bar", - inter.TestTwoArgs("foo", "bar")); - IList temp = new List(); - inter.TestVoid(temp); - Assert.AreEqual("my void result", temp[0]); - Assert.AreEqual(10, inter.TestPrimitive(10)); - Assert.AreEqual(1000L, inter.TestStruct(new DateTime(1000)).Ticks); - inter.TestProperty = "my property"; - Assert.AreEqual("my property", inter.TestProperty); - } - } -} \ No newline at end of file diff --git a/FrameworkTests/SafeTypeTest.cs b/FrameworkTests/SafeTypeTest.cs deleted file mode 100644 index 23f8a5d..0000000 --- a/FrameworkTests/SafeTypeTest.cs +++ /dev/null @@ -1,46 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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 NUnit.Framework; -using NUnit.Framework.SyntaxHelpers; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Framework.Api.Operations; -namespace FrameworkTests -{ - [TestFixture] - public class SafeTypeTest - { - [Test] - public void TestSafeType() - { - //compile-time type safe - SafeType op = - SafeType.Get(); - Assert.AreEqual(typeof(ScriptOnResourceApiOp), op.RawType); - //runtime type safe. needed for marshalling code, etc - op = - SafeType.ForRawType(typeof(SchemaApiOp)); - Assert.AreEqual(typeof(SchemaApiOp), op.RawType); - } - } -} diff --git a/FrameworkTests/ScriptTests.cs b/FrameworkTests/ScriptTests.cs deleted file mode 100644 index 2d6ef10..0000000 --- a/FrameworkTests/ScriptTests.cs +++ /dev/null @@ -1,147 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Reflection; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Common.Script; -using Org.IdentityConnectors.Framework.Common.Objects; -using NUnit.Framework; -using NUnit.Framework.SyntaxHelpers; - -namespace FrameworkTests -{ - /// - /// Description of ScriptTests. - /// - [TestFixture] - public class ScriptTests - { - [Test] - public void testBooScripting() - { - ScriptExecutorFactory factory = ScriptExecutorFactory.NewInstance("BOO"); - ScriptExecutor exe = factory.NewScriptExecutor(new Assembly[0], "x", false); - IDictionary vals = new Dictionary(); - vals["x"] = 1; - Assert.AreEqual(1, exe.Execute(vals)); - vals["x"] = 2; - Assert.AreEqual(2, exe.Execute(vals)); - } - [Test] - public void testShellScripting() - { - ScriptExecutorFactory factory = ScriptExecutorFactory.NewInstance("Shell"); - ScriptExecutor exe = factory.NewScriptExecutor(new Assembly[0], "echo bob", false); - IDictionary vals = new Dictionary(); - Assert.AreEqual(0, exe.Execute(vals)); - } - [Test] - [ExpectedException(typeof(ArgumentException))] - public void testUnsupported() - { - ScriptExecutorFactory.NewInstance("fadsflkj"); - } - - [Test] - public void testBasic() - { - ScriptBuilder builder = new ScriptBuilder(); - builder.ScriptLanguage = "Groovy"; - builder.ScriptText = "print 'foo'"; - Script s1 = builder.Build(); - Assert.AreEqual("Groovy", s1.ScriptLanguage); - Assert.AreEqual("print 'foo'", s1.ScriptText); - builder = new ScriptBuilder(); - builder.ScriptLanguage = "Groovy"; - builder.ScriptText = "print 'foo'"; - Script s2 = builder.Build(); - Assert.AreEqual(s1, s2); - Assert.AreEqual(s1.GetHashCode(), s2.GetHashCode()); - } - - [Test] - public void testLanguageNotBlank() - { - try - { - ScriptBuilder builder = new ScriptBuilder(); - builder.ScriptText = "print 'foo'"; - builder.Build(); - Assert.Fail(); - } - catch (ArgumentException) - { - // OK. - } - - try - { - ScriptBuilder builder = new ScriptBuilder(); - builder.ScriptText = "print 'foo'"; - builder.ScriptLanguage = ""; - builder.Build(); - Assert.Fail(); - } - catch (ArgumentException) - { - // OK. - } - - try - { - ScriptBuilder builder = new ScriptBuilder(); - builder.ScriptText = "print 'foo'"; - builder.ScriptLanguage = " "; - builder.Build(); - Assert.Fail(); - } - catch (ArgumentException) - { - // OK. - } - } - - [Test] - public void testTextNotNull() - { - ScriptBuilder builder = new ScriptBuilder(); - try - { - builder.ScriptLanguage = "Groovy"; - builder.Build(); - Assert.Fail(); - } - catch (ArgumentNullException) - { - // OK. - } - - // The text can be empty. - builder = new ScriptBuilder(); - builder.ScriptLanguage = "Groovy"; - builder.ScriptText = ""; - builder.Build(); - } - } -} diff --git a/FrameworkTests/TestHelperTests.cs b/FrameworkTests/TestHelperTests.cs deleted file mode 100644 index dcef674..0000000 --- a/FrameworkTests/TestHelperTests.cs +++ /dev/null @@ -1,248 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.IO; -using System.Xml; -using System.Collections.Generic; -using System.Linq; - -using NUnit.Framework; - -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Spi; -using Org.IdentityConnectors.Test.Common; -using System.Text; -using System.Diagnostics; -using Org.IdentityConnectors.Common; - -namespace FrameworkTests -{ - /// - /// Description of TestHelperTests. - /// - [TestFixture] - public class TestHelperTests - { - [Test] - public void TestReadConfiguration() - { - using (var memoryStream = new MemoryStream()) - { - var properties = new Dictionary() - { - {"bob", "bobsValue"}, - {"bob2", "bob2sValue"} - }; - - CreateXmlConfiguration(memoryStream, properties); - - memoryStream.Seek(0, SeekOrigin.Begin); - // load the properties files - var dict = TestHelpers.ReadConfiguration(memoryStream); - foreach (var property in properties) - { - Assert.AreEqual(dict[property.Key], property.Value); - } - } - } - - /// - /// Creates an XML configuration in the specified stream based on the . - /// - /// The output stream. - /// The properties to be stored. - /// The caller is responsible for closing the stream. - private static void CreateXmlConfiguration(Stream stream, IDictionary properties) - { - var settings = new XmlWriterSettings - { - Encoding = Encoding.UTF8, - CloseOutput = false - }; - using (var writer = XmlWriter.Create(stream, settings)) - { - writer.WriteStartDocument(); - writer.WriteStartElement("config"); - foreach (var property in properties) - { - writer.WriteStartElement("property"); - writer.WriteAttributeString("name", property.Key); - writer.WriteAttributeString("value", property.Value); - writer.WriteEndElement(); - } - writer.WriteEndDocument(); - writer.Flush(); - } - } - - [Test] - public void TestGetProperties() - { - const string testConfigName = "myconfig"; - Type connectorType = typeof(Org.IdentityConnectors.TestConnector.FakeConnector); - - //store environment variables, they must be restored at the end - var oldTestConfig = Environment.GetEnvironmentVariable(TestHelpers.TestConfigEVName); - var oldPrivateConfigRoot = Environment.GetEnvironmentVariable(TestHelpers.PrivateConfigRootEVName); - Environment.SetEnvironmentVariable(TestHelpers.TestConfigEVName, testConfigName); - - var privateConfigRoot = Path.GetTempPath(); - - try - { - //set the TestHelpers.PrivateConfigRootEVName environment variable used by this test - Environment.SetEnvironmentVariable(TestHelpers.PrivateConfigRootEVName, privateConfigRoot); - - //at the end the created dir structure must be deleted, hence we need to store this - privateConfigRoot = Path.Combine(privateConfigRoot, "config"); - - var privateConfigPath = Path.Combine(Path.Combine(privateConfigRoot, connectorType.FullName), - "config-private"); - //create the directory structure for the general and the specific "testConfigName" private config - Directory.CreateDirectory(Path.Combine(privateConfigPath, testConfigName)); - - //create general private config file - using (var configFile = File.Create(Path.Combine(privateConfigPath, "config.xml"))) - { - CreateXmlConfiguration(configFile, new Dictionary() {{"privatekey", "value"}}); - } - - //create specific private config file - using (var configFile = File.Create(Path.Combine(Path.Combine(privateConfigPath, testConfigName), "config.xml"))) - { - CreateXmlConfiguration(configFile, new Dictionary() {{"myconfig.privatekey", "value"}}); - } - - PropertyBag bag1 = TestHelpers.GetProperties(connectorType); - CheckProperties(bag1); - PropertyBag bag2 = TestHelpers.GetProperties(connectorType); - Assert.AreSame(bag1, bag2, "TestHepers must create the same PropertyBag for the same connector"); - } - finally - { - if (oldTestConfig != null) - { - Environment.SetEnvironmentVariable(TestHelpers.TestConfigEVName, oldTestConfig); - } - if (oldPrivateConfigRoot != null) - { - Environment.SetEnvironmentVariable(TestHelpers.PrivateConfigRootEVName, oldPrivateConfigRoot); - } - - try - { - if (Directory.Exists(privateConfigRoot)) - { - Directory.Delete(privateConfigRoot, true); - } - } - catch (Exception ex) - { - //although, something bad happened there is no need to fail the test since the next time it will overwrite - //the temporary files if any exists - Trace.TraceWarning(ex.ToString()); - } - } - } - - private static void CheckProperties(PropertyBag bag) - { - var properties = new Dictionary - { - {"Help", "Me"}, - {"publickey", "value"}, - {"myconfig.publickey", "value"}, - {"privatekey", "value"}, - {"myconfig.privatekey", "value"} - }; - - var bagElements = bag.ToDictionary(); - Assert.That( - CollectionUtil.DictionariesEqual(properties, bagElements) && CollectionUtil.DictionariesEqual(bagElements, properties), - "Expected test properties not equal"); - } - - [Test] - public void testFillConfiguration() - { - TestConfiguration testConfig = new TestConfiguration(); - // There is no "Foo" property in the config bean. We want to ensure - // that TestHelpers.FillConfiguration() does not fail for unknown properties. - IDictionary configData = new Dictionary(); - configData["Host"] = "example.com"; - configData["Port"] = 1234; - configData["Foo"] = "bar"; - TestHelpers.FillConfiguration(testConfig, configData); - - Assert.AreEqual("example.com", testConfig.Host); - Assert.AreEqual(1234, testConfig.Port); - } - - public class TestConfiguration : Configuration - { - - public ConnectorMessages ConnectorMessages - { - get - { - return null; - } - set - { - Assert.Fail("Should not set ConnectorMessages"); - } - } - - public void Validate() - { - Assert.Fail("Should not call Validate()"); - } - - public String Host { get; set; } - - public int Port { get; set; } - - public String Unused { get; set; } - } - } -} - -namespace Org.IdentityConnectors.TestConnector -{ - public class FakeConnector : Connector - { - #region Connector Members - public void Init(Configuration configuration) - { - throw new NotImplementedException(); - } - #endregion - - #region IDisposable Members - public void Dispose() - { - throw new NotImplementedException(); - } - #endregion - } -} diff --git a/FrameworkTests/TestUtil.cs b/FrameworkTests/TestUtil.cs deleted file mode 100644 index e72737a..0000000 --- a/FrameworkTests/TestUtil.cs +++ /dev/null @@ -1,53 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Diagnostics; - -namespace FrameworkTests -{ - /// - /// Description of TestUtil. - /// - public static class TestUtil - { - private static readonly object LOCK = new Object(); - private static bool _initialized; - - - public static void InitializeLogging() - { - lock (LOCK) - { - if (!_initialized) - { - ConsoleTraceListener listener = - new ConsoleTraceListener(); - listener.TraceOutputOptions = - TraceOptions.ThreadId | TraceOptions.Timestamp; - Trace.Listeners.Add(listener); - _initialized = true; - } - } - } - } -} diff --git a/FrameworkTests/UpdateImplTests.cs b/FrameworkTests/UpdateImplTests.cs deleted file mode 100644 index 2bce250..0000000 --- a/FrameworkTests/UpdateImplTests.cs +++ /dev/null @@ -1,228 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Security; -using NUnit.Framework; -using NUnit.Framework.SyntaxHelpers; -using System.Collections.Generic; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Framework.Api; -using Org.IdentityConnectors.Framework.Api.Operations; -using Org.IdentityConnectors.Framework.Impl.Api.Local.Operations; -using Org.IdentityConnectors.Framework.Common.Objects; -namespace FrameworkTests -{ - /// - /// Description of UpdateImplTests. - /// - [TestFixture] - public class UpdateImplTests - { - [Test] - [ExpectedException(typeof(ArgumentNullException))] - public void ValidateUidArg() - { - UpdateImpl.ValidateInput(ObjectClass.ACCOUNT, null, new HashSet(), true); - } - [Test] - [ExpectedException(typeof(ArgumentNullException))] - public void ValidateObjectClassArg() - { - UpdateImpl.ValidateInput(null, new Uid("foo"), new HashSet(), true); - } - - [Test] - [ExpectedException(typeof(ArgumentNullException))] - public void ValidateAttrsArg() - { - UpdateImpl.ValidateInput(ObjectClass.ACCOUNT, new Uid("foo"), null, true); - } - - [Test] - [ExpectedException(typeof(ArgumentException))] - public void ValidateUidAttribute() - { - HashSet attrs = new HashSet(); - attrs.Add(new Uid("foo")); - UpdateImpl.ValidateInput(ObjectClass.ACCOUNT, new Uid("foo"), attrs, true); - } - - [Test] - [ExpectedException(typeof(ArgumentException))] - public void ValidateAddWithNullAttribute() - { - ICollection attrs = new HashSet(); - attrs.Add(ConnectorAttributeBuilder.Build("something")); - UpdateImpl.ValidateInput(ObjectClass.ACCOUNT, new Uid("foo"), attrs, true); - } - - [Test] - [ExpectedException(typeof(ArgumentException))] - public void ValidateAttemptToAddName() - { - ICollection attrs = new HashSet(); - attrs.Add(new Name("fadf")); - UpdateImpl.ValidateInput(ObjectClass.ACCOUNT, new Uid("foo"), attrs, true); - } - - [Test] - public void ValidateAttemptToAddDeleteOperationalAttribute() - { - // list of all the operational attributes.. - ICollection list = new List(); - list.Add(ConnectorAttributeBuilder.BuildEnabled(false)); - list.Add(ConnectorAttributeBuilder.BuildLockOut(true)); - list.Add(ConnectorAttributeBuilder.BuildCurrentPassword(newSecureString("fadsf"))); - list.Add(ConnectorAttributeBuilder.BuildPasswordExpirationDate(DateTime.Now)); - list.Add(ConnectorAttributeBuilder.BuildPassword(newSecureString("fadsf"))); - foreach (ConnectorAttribute attr in list) - { - ICollection attrs = new HashSet(); - attrs.Add(attr); - try - { - UpdateImpl.ValidateInput(ObjectClass.ACCOUNT, new Uid("1"), attrs, true); - Assert.Fail("Failed: " + attr.Name); - } - catch (ArgumentException) - { - // this is a good thing.. - } - } - } - - private static SecureString newSecureString(string password) - { - SecureString rv = new SecureString(); - foreach (char c in password.ToCharArray()) - { - rv.AppendChar(c); - } - return rv; - } - - /// - /// Validate two collections are equal. (Not fast but effective) - /// - public static bool AreEqual(ICollection arg1, - ICollection arg2) - { - if (arg1.Count != arg2.Count) - { - return false; - } - foreach (ConnectorAttribute attr in arg1) - { - if (!arg2.Contains(attr)) - { - return false; - } - } - return true; - } - [Test] - public void MergeAddAttribute() - { - UpdateImpl up = new UpdateImpl(null, null); - ICollection actual; - ICollection baseAttrs = CollectionUtil.NewSet(); - ICollection expected = CollectionUtil.NewSet(); - ICollection changeset = CollectionUtil.NewSet(); - // attempt to add a value to an attribute.. - ConnectorAttribute cattr = ConnectorAttributeBuilder.Build("abc", 2); - changeset.Add(cattr); - expected.Add(ConnectorAttributeBuilder.Build("abc", 2)); - actual = up.Merge(changeset, baseAttrs, true); - Assert.IsTrue(AreEqual(expected, actual)); - } - - [Test] - public void MergeAddToExistingAttribute() - { - UpdateImpl up = new UpdateImpl(null, null); - ICollection actual; - ICollection baseAttrs = CollectionUtil.NewSet(); - ICollection expected = CollectionUtil.NewSet(); - ICollection changeset = CollectionUtil.NewSet(); - // attempt to add a value to an attribute.. - ConnectorAttribute battr = ConnectorAttributeBuilder.Build("abc", 1); - ConnectorAttribute cattr = ConnectorAttributeBuilder.Build("abc", 2); - baseAttrs.Add(battr); - changeset.Add(cattr); - expected.Add(ConnectorAttributeBuilder.Build("abc", 1, 2)); - actual = up.Merge(changeset, baseAttrs, true); - Assert.IsTrue(AreEqual(expected, actual)); - } - - [Test] - public void MergeDeleteNonExistentAttribute() - { - UpdateImpl up = new UpdateImpl(null, null); - ICollection actual; - ICollection baseAttrs = CollectionUtil.NewSet(); - ICollection expected = CollectionUtil.NewSet(); - ICollection changeset = CollectionUtil.NewSet(); - // attempt to add a value to an attribute.. - ConnectorAttribute cattr = ConnectorAttributeBuilder.Build("abc", 2); - changeset.Add(cattr); - actual = up.Merge(changeset, baseAttrs, false); - Assert.IsTrue(AreEqual(expected, actual)); - } - - [Test] - public void MergeDeleteToExistingAttribute() - { - UpdateImpl up = new UpdateImpl(null, null); - ICollection actual; - ICollection baseAttrs = CollectionUtil.NewSet(); - ICollection expected = CollectionUtil.NewSet(); - ICollection changeset = CollectionUtil.NewSet(); - // attempt to add a value to an attribute.. - ConnectorAttribute battr = ConnectorAttributeBuilder.Build("abc", 1, 2); - ConnectorAttribute cattr = ConnectorAttributeBuilder.Build("abc", 2); - baseAttrs.Add(battr); - changeset.Add(cattr); - expected.Add(ConnectorAttributeBuilder.Build("abc", 1)); - actual = up.Merge(changeset, baseAttrs, false); - Assert.IsTrue(AreEqual(expected, actual)); - } - - [Test] - public void MergeDeleteToExistingAttributeCompletely() - { - UpdateImpl up = new UpdateImpl(null, null); - ICollection actual; - ICollection baseAttrs = CollectionUtil.NewSet(); - ICollection expected = CollectionUtil.NewSet(); - ICollection changeset = CollectionUtil.NewSet(); - // attempt to add a value to an attribute.. - ConnectorAttribute battr = ConnectorAttributeBuilder.Build("abc", 1, 2); - ConnectorAttribute cattr = ConnectorAttributeBuilder.Build("abc", 1, 2); - baseAttrs.Add(battr); - changeset.Add(cattr); - expected.Add(ConnectorAttributeBuilder.Build("abc")); - actual = up.Merge(changeset, baseAttrs, false); - Assert.IsTrue(AreEqual(expected, actual)); - } - } -} diff --git a/FrameworkTests/app.config b/FrameworkTests/app.config deleted file mode 100644 index e228e5f..0000000 --- a/FrameworkTests/app.config +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/FrameworkTests/version.template b/FrameworkTests/version.template deleted file mode 100644 index db70057..0000000 --- a/FrameworkTests/version.template +++ /dev/null @@ -1 +0,0 @@ -1.2.0.0 diff --git a/Service/Program.cs b/Service/Program.cs deleted file mode 100644 index 1cb3337..0000000 --- a/Service/Program.cs +++ /dev/null @@ -1,251 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.ComponentModel; -using System.Configuration; -using System.Configuration.Install; -using System.Collections.Generic; -using System.Security; -using System.Reflection; -using System.ServiceProcess; -using System.Text; -using Org.IdentityConnectors.Common.Security; - -namespace Org.IdentityConnectors.Framework.Service -{ - - static class Program - { - private const string OPT_SERVICE_NAME = "/serviceName"; - - private static void Usage() - { - Console.WriteLine("Usage: ConnectorServer.exe [option], where command is one of the following: "); - Console.WriteLine(" /install [/serviceName ] - Installs the service."); - Console.WriteLine(" /uninstall [/serviceName ] - Uninstalls the service."); - Console.WriteLine(" /run - Runs the service from the console."); - Console.WriteLine(" /setKey [] - Sets the connector server key."); - } - - private static IDictionary ParseOptions(string[] args) - { - IDictionary rv = new Dictionary(); - String serviceName = null; - for (int i = 1; i < args.Length; i++) - { - String opt = args[i].ToLower(); - if (OPT_SERVICE_NAME.ToLower().Equals(opt)) - { - i++; - if (i < args.Length) - { - serviceName = args[i]; - } - else - { - Usage(); - return null; - } - } - else - { - Usage(); - return null; - } - } - rv["/serviceName"] = serviceName; - return rv; - } - - /// - /// This method starts the service. - /// - static void Main(string[] args) - { - if (args.Length == 0) - { - //no args - start the service - ServiceBase.Run(new ServiceBase[] { new Service() }); - } - else - { - String cmd = args[0].ToLower(); - if (cmd.Equals("/setkey")) - { - if (args.Length > 2) - { - Usage(); - return; - } - DoSetKey(args.Length > 1 ? args[1] : null); - return; - } - IDictionary options = - ParseOptions(args); - if (options == null) - { - //there's a parse error in the options, return - return; - } - if ("/install".Equals(cmd)) - { - DoInstall(options); - } - else if ("/uninstall".Equals(cmd)) - { - DoUninstall(options); - } - else if ("/run".Equals(cmd)) - { - DoRun(options); - } - else - { - Usage(); - return; - } - } - } - - private static void DoInstall(IDictionary options) - { - String serviceName = options[OPT_SERVICE_NAME]; - if (serviceName != null) - { - ProjectInstaller.ServiceName = serviceName; - } - TransactedInstaller ti = new TransactedInstaller(); - string[] cmdline = - { - Assembly.GetExecutingAssembly ().Location - }; - AssemblyInstaller ai = new AssemblyInstaller( - cmdline[0], - new string[0]); - ti.Installers.Add(ai); - InstallContext ctx = new InstallContext("install.log", - cmdline); - ti.Context = ctx; - ti.Install(new System.Collections.Hashtable()); - } - - private static void DoUninstall(IDictionary options) - { - String serviceName = options[OPT_SERVICE_NAME]; - if (serviceName != null) - { - ProjectInstaller.ServiceName = serviceName; - } - TransactedInstaller ti = new TransactedInstaller(); - string[] cmdline = - { - Assembly.GetExecutingAssembly ().Location - }; - AssemblyInstaller ai = new AssemblyInstaller( - cmdline[0], - new string[0]); - ti.Installers.Add(ai); - InstallContext ctx = new InstallContext("uninstall.log", - cmdline); - ti.Context = ctx; - ti.Uninstall(null); - } - - private static void DoRun(IDictionary options) - { - Service svc = new Service(); - - svc.StartService(new String[0]); - - Console.WriteLine("Press q to shutdown."); - Console.WriteLine("Press t for a thread dump."); - - while (true) - { - ConsoleKeyInfo info = Console.ReadKey(); - if (info.KeyChar == 'q') - { - break; - } - else if (info.KeyChar == 't') - { - svc.DumpRequests(); - } - } - - svc.StopService(); - } - - private static GuardedString ReadPassword() - { - GuardedString rv = new GuardedString(); - while (true) - { - ConsoleKeyInfo info = Console.ReadKey(true); - if (info.Key == ConsoleKey.Enter) - { - Console.WriteLine(); - rv.MakeReadOnly(); - return rv; - } - else - { - Console.Write("*"); - rv.AppendChar(info.KeyChar); - } - } - } - - private static void DoSetKey(string key) - { - GuardedString str; - if (key == null) - { - Console.Write("Enter Key: "); - GuardedString v1 = ReadPassword(); - Console.Write("Confirm Key: "); - GuardedString v2 = ReadPassword(); - if (!v1.Equals(v2)) - { - Console.WriteLine("Error: Key mismatch."); - return; - } - str = v2; - } - else - { - str = new GuardedString(); - foreach (char c in key.ToCharArray()) - { - str.AppendChar(c); - } - } - Configuration config = - ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); - config.AppSettings.Settings.Remove(Service.PROP_KEY); - config.AppSettings.Settings.Add(Service.PROP_KEY, str.GetBase64SHA1Hash()); - config.Save(ConfigurationSaveMode.Modified); - Console.WriteLine("Key Updated."); - } - } -} \ No newline at end of file diff --git a/Service/ProjectInstaller.cs b/Service/ProjectInstaller.cs deleted file mode 100644 index 103917f..0000000 --- a/Service/ProjectInstaller.cs +++ /dev/null @@ -1,56 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.ComponentModel; -using System.Configuration.Install; -using System.ServiceProcess; - -namespace Org.IdentityConnectors.Framework.Service -{ - [RunInstaller(true)] - public class ProjectInstaller : Installer - { - public static string ServiceName { get; set; } - - static ProjectInstaller() - { - ServiceName = "Connector Server"; - } - - private ServiceProcessInstaller serviceProcessInstaller; - private ServiceInstaller serviceInstaller; - - public ProjectInstaller() - { - serviceProcessInstaller = new ServiceProcessInstaller(); - serviceInstaller = new ServiceInstaller(); - - // Here you can set properties on serviceProcessInstaller or register event handlers - serviceProcessInstaller.Account = ServiceAccount.LocalSystem; - - serviceInstaller.ServiceName = ServiceName; - this.Installers.AddRange(new Installer[] { serviceProcessInstaller, serviceInstaller }); - } - } -} diff --git a/Service/Service.cs b/Service/Service.cs deleted file mode 100644 index 54a43dc..0000000 --- a/Service/Service.cs +++ /dev/null @@ -1,182 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Collections.Specialized; -using System.ComponentModel; -using System.Configuration; -using System.Data; -using System.Diagnostics; -using System.IO; -using System.Reflection; -using System.Security.Cryptography.X509Certificates; -using System.ServiceProcess; -using System.Text; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Framework.Server; - -namespace Org.IdentityConnectors.Framework.Service -{ - public class Service : ServiceBase - { - private const string PROP_PORT = "connectorserver.port"; - private const string PROP_SSL = "connectorserver.usessl"; - private const string PROP_CERTSTORE = "connectorserver.certificatestorename"; - private const string PROP_IFADDRESS = "connectorserver.ifaddress"; - public const string PROP_KEY = "connectorserver.key"; - - private ConnectorServer _server; - - public Service() - { - } - - public void DumpRequests() - { - _server.DumpRequests(); - } - - - /// - /// Clean up any resources being used. - /// - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - } - - private void initializeCurrentDirectory() - { - Assembly assembly = - Assembly.GetExecutingAssembly(); - FileInfo thisAssemblyFile = - new FileInfo(assembly.Location); - DirectoryInfo directory = - thisAssemblyFile.Directory; - Environment.CurrentDirectory = - directory.FullName; - - } - - private NameValueCollection GetApplicationSettings() - { - return ConfigurationManager.AppSettings; - } - - private X509Certificate GetCertificate() - { - NameValueCollection settings = - GetApplicationSettings(); - String storeName = settings.Get(PROP_CERTSTORE); - if (storeName == null) { - throw new Org.IdentityConnectors.Framework.Common.Exceptions.ConfigurationException("Missing required configuration setting: "+PROP_CERTSTORE); - } - - X509Store store = new X509Store(storeName, - StoreLocation.LocalMachine); - - store.Open(OpenFlags.ReadOnly|OpenFlags.OpenExistingOnly); - X509CertificateCollection certificates = store.Certificates; - if ( certificates.Count != 1 ) { - throw new Org.IdentityConnectors.Framework.Common.Exceptions.ConfigurationException("There is supported to be exactly one certificate in the store: "+storeName); - } - X509Certificate certificate = store.Certificates[0]; - store.Close(); - return certificate; - } - - public void StartService(string [] args) - { - OnStart(args); - } - - /// - /// Start this service. - /// - protected override void OnStart(string[] args) - { - try { - initializeCurrentDirectory(); - Trace.TraceInformation("Starting connector server: "+Environment.CurrentDirectory); - NameValueCollection settings = - GetApplicationSettings(); - String portStr = - settings.Get(PROP_PORT); - if ( portStr == null ) { - throw new Org.IdentityConnectors.Framework.Common.Exceptions.ConfigurationException("Missing required configuration property: "+PROP_PORT); - } - String keyHash = settings.Get(PROP_KEY); - if ( keyHash == null ) { - throw new Org.IdentityConnectors.Framework.Common.Exceptions.ConfigurationException("Missing required configuration property: "+PROP_KEY); - } - - int port = Int32.Parse(portStr); - bool useSSL = Boolean.Parse(settings.Get(PROP_SSL)??"false"); - _server = ConnectorServer.NewInstance(); - _server.Port = port; - _server.UseSSL = useSSL; - _server.KeyHash = keyHash; - if (useSSL) { - _server.ServerCertificate = - GetCertificate(); - } - String ifaddress = settings.Get(PROP_IFADDRESS); - if ( ifaddress != null ) { - _server.IfAddress = - IOUtil.GetIPAddress(ifaddress); - } - _server.Start(); - Trace.TraceInformation("Started connector server"); - } - catch (Exception e) { - TraceUtil.TraceException("Exception occured starting connector server", - e); - throw; - } - } - - public void StopService() - { - OnStop(); - } - - - /// - /// Stop this service. - /// - protected override void OnStop() - { - try { - Trace.TraceInformation("Stopping connector server"); - if (_server != null) { - _server.Stop(); - } - Trace.TraceInformation("Stopped connector server"); - } - catch (Exception e) { - TraceUtil.TraceException("Exception occured stopping connector server", - e); - } - } - } -} diff --git a/Service/Service.csproj b/Service/Service.csproj deleted file mode 100644 index 6e1f939..0000000 --- a/Service/Service.csproj +++ /dev/null @@ -1,114 +0,0 @@ - - - - {A9D6374A-D51F-4FA3-8C02-5B1D23FAA82E} - Debug - AnyCPU - Exe - Sun.OpenConnectors.Framework.Service - ConnectorServer - Service - v3.5 - False - false - true - - - prompt - ./bin/Debug/ - true - Full - False - True - DEBUG;TRACE - Exe - ConnectorServer - False - 4 - - - ./bin/Release/ - False - pdbonly - True - False - TRACE - prompt - Exe - ConnectorServer - False - 4 - - - False - Auto - 4194304 - AnyCPU - 4096 - - - - - - - - 3.5 - - - - - 3.5 - - - - - - - - Component - - - Component - - - - - - - - - - {F140E8DA-52B4-4159-992A-9DA10EA8EEFB} - Common - - - {5B011775-B121-4EEE-A410-BA2D2F5BFB8B} - FrameworkInternal - - - {8B24461B-456A-4032-89A1-CD418F7B5B62} - Framework - - - diff --git a/Service/app.config b/Service/app.config deleted file mode 100644 index 342a797..0000000 --- a/Service/app.config +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Service/version.template b/Service/version.template deleted file mode 100644 index db70057..0000000 --- a/Service/version.template +++ /dev/null @@ -1 +0,0 @@ -1.2.0.0 diff --git a/ServiceInstall/ExtBuild.proj b/ServiceInstall/ExtBuild.proj deleted file mode 100644 index d8d676b..0000000 --- a/ServiceInstall/ExtBuild.proj +++ /dev/null @@ -1,65 +0,0 @@ - - - - Debug - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ServiceInstall/File.bottom b/ServiceInstall/File.bottom deleted file mode 100644 index 9e4c610..0000000 --- a/ServiceInstall/File.bottom +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/ServiceInstall/File.top b/ServiceInstall/File.top deleted file mode 100644 index c046613..0000000 --- a/ServiceInstall/File.top +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - diff --git a/ServiceInstall/ServiceInstall.wixproj b/ServiceInstall/ServiceInstall.wixproj deleted file mode 100644 index 45e2095..0000000 --- a/ServiceInstall/ServiceInstall.wixproj +++ /dev/null @@ -1,72 +0,0 @@ - - - - {1CBA8F74-050C-432B-8437-08BD13BDC684} - Debug - AnyCPU - Package - ServiceInstall - ServiceInstall - $(WIX_HOME) - $(WixToolPath)\wix.targets - $(WixToolPath)\WixTasks.dll - ICE45 - WixUILicenseRtf=license.rtf - - - prompt - 4 - AnyCPU - bin\Debug\ - True - Full - False - True - DEBUG;TRACE - - - pdbonly - bin\Release\ - TRACE - prompt - 4 - AnyCPU - False - True - False - - - - - $(WixToolPath)\WixUIExtension.dll - - - - - - - - - - diff --git a/ServiceInstall/Setup.wxs b/ServiceInstall/Setup.wxs deleted file mode 100644 index f9e70b8..0000000 --- a/ServiceInstall/Setup.wxs +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/ServiceInstall/license.rtf b/ServiceInstall/license.rtf deleted file mode 100644 index 5ecc7cf..0000000 --- a/ServiceInstall/license.rtf +++ /dev/null @@ -1,30 +0,0 @@ -{\rtf1\ansi\deff0\adeflang1025 -{\fonttbl{\f0\froman\fprq2\fcharset0 Thorndale{\*\falt Times New Roman};}{\f1\froman\fprq2\fcharset0 Thorndale{\*\falt Times New Roman};}{\f2\fswiss\fprq2\fcharset0 Albany{\*\falt Arial};}{\f3\fnil\fprq2\fcharset0 Andale Sans UI{\*\falt Arial Unicode MS};}{\f4\fnil\fprq2\fcharset0 Tahoma;}{\f5\fnil\fprq0\fcharset0 Tahoma;}} -{\colortbl;\red0\green0\blue0;\red128\green128\blue128;} -{\stylesheet{\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\snext1 Normal;} -{\s2\sb240\sa120\keepn\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\afs28\lang255\ltrch\dbch\langfe255\hich\f2\fs28\lang1033\loch\f2\fs28\lang1033\sbasedon1\snext3 Heading;} -{\s3\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\sbasedon1\snext3 Body Text;} -{\s4\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\sbasedon3\snext4 List;} -{\s5\sb120\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ai\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1033\i\loch\f0\fs24\lang1033\i\sbasedon1\snext5 caption;} -{\s6\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\sbasedon1\snext6 Index;} -} -{\info{\author William Droste}{\creatim\yr2008\mo8\dy7\hr10\min50}{\revtim\yr0\mo0\dy0\hr0\min0}{\printim\yr0\mo0\dy0\hr0\min0}{\comment StarWriter}{\vern6800}}\deftab709 -{\*\pgdsctbl -{\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\pgdscnxt0 Standard;}} -\paperh15840\paperw12240\margl1134\margr1134\margt1134\margb1134\sectd\sbknone\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc -\pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Copyright \'a9 2008 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, California 95054, U.S.A. All rights reserved.} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch }{\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 U.S. Government Rights - Commercial software. Government users are subject to the Sun Microsystems, Inc. standard license agreement and applicable provisions of the FAR and its supplements.} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch }{\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Use is subject to license terms.} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch }{\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 This distribution may include materials developed by third parties.} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch }{\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Sun, Sun Microsystems, the Sun logo, Java and Project Identity Connectors are trademarks or registered trademarks of Sun Microsystems, Inc. in the U.S. and other countries.} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch }{\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 UNIX is a registered trademark in the U.S. and other countries, exclusively licensed through X/Open Company, Ltd.} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch }{\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 This product is covered and controlled by U.S. Export Control laws and may be subject to the export or import laws in other countries. Nuclear, missile, chemical biological weapons or nuclear maritime end uses or end users, whether direct or indirec -t, are strictly prohibited. Export or reexport to countries subject to U.S. embargo or to entities identified on U.S. export exclusion lists, including, but not limited to, the denied persons and specially designated nationals lists is strictly prohibited. - } -\par } \ No newline at end of file diff --git a/ShellScriptExecutorFactory/ShellScriptExecutorFactory.cs b/ShellScriptExecutorFactory/ShellScriptExecutorFactory.cs deleted file mode 100644 index 64367a3..0000000 --- a/ShellScriptExecutorFactory/ShellScriptExecutorFactory.cs +++ /dev/null @@ -1,151 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.IO; -using System.Security; -using System.Diagnostics; -using System.Reflection; -using System.Collections.Generic; -using System.Text.RegularExpressions; -using Org.IdentityConnectors.Common.Security; - -namespace Org.IdentityConnectors.Common.Script.Shell -{ - - /// - /// Process shell scripts. Valid arguments are below, the rest will be - /// used as environment variables. The return is the exit code of the - /// process. - ///
    - ///
  • USERNAME - name of the user to run this script as..
  • - ///
  • PASSWORD - (GuardedString or SecureString) password for the user to run this script as..
  • - ///
  • WORKINGDIR - working directory run this script in..
  • - ///
  • TIMEOUT - timeout waiting for script to finish in ms (default: 30 secs)
  • - ///
- ///
- [ScriptExecutorFactoryClass("Shell")] - public class ShellScriptExecutorFactory : ScriptExecutorFactory - { - - /// - /// Creates a script executor give the Shell script. - /// - override - public ScriptExecutor NewScriptExecutor(Assembly[] refs, string script, bool compile) - { - return new ShellScriptExecutor(script); - } - - /// - /// Processes the script. - /// - class ShellScriptExecutor : ScriptExecutor - { - private readonly string _script; - - public ShellScriptExecutor(string script) - { - _script = script; - } - public object Execute(IDictionary arguments) - { - // create the process info.. - Process process = new Process(); - // set the defaults.. - process.StartInfo.CreateNoWindow = true; - process.StartInfo.UseShellExecute = true; - // set the default timeout.. - int timeout = 1000 * 30; // 30 secss - // if there are any environment varibles set to false.. - process.StartInfo.UseShellExecute = arguments.Count == 0; - // take out username and password if they're in the options. - foreach (KeyValuePair kv in arguments) - { - if (kv.Key.ToUpper().Equals("USERNAME")) - { - string domainUser = kv.Value.ToString(); - string[] split = domainUser.Split(new char[] { '\\' }); - if (split.Length == 1) - { - process.StartInfo.UserName = split[0]; - } - else - { - process.StartInfo.Domain = split[0]; - process.StartInfo.UserName = split[1]; - } - } - else if (kv.Key.ToUpper().Equals("PASSWORD")) - { - if (kv.Value is SecureString) - { - process.StartInfo.Password = (SecureString)kv.Value; - } - else if (kv.Value is GuardedString) - { - process.StartInfo.Password = ((GuardedString)kv.Value).ToSecureString(); - } - else - { - throw new ArgumentException("Invalid type for password."); - } - } - else if (kv.Key.ToUpper().Equals("WORKINGDIR")) - { - process.StartInfo.WorkingDirectory = kv.Value.ToString(); - } - else if (kv.Key.ToUpper().Equals("TIMEOUT")) - { - timeout = Int32.Parse(kv.Value.ToString()); - } - else - { - process.StartInfo.EnvironmentVariables[kv.Key] = kv.Value.ToString(); - } - } - // write out the script.. - string fn = Path.GetTempFileName() + ".cmd"; - using (StreamWriter sw = new StreamWriter(fn)) - { - sw.Write(_script); - } - // set temp file.. - process.StartInfo.FileName = fn; - // execute script.. - process.Start(); - // wait for the process to exit.. - if (!process.WaitForExit(timeout)) - { - process.Close(); - throw new TimeoutException("Script failed to exit in time!"); - } - int exitCode = process.ExitCode; - // close up the process and return the exit code.. - process.Close(); - // clean up temp file.. - File.Delete(fn); - return exitCode; - } - } - } -} diff --git a/ShellScriptExecutorFactory/ShellScriptExecutorFactory.csproj b/ShellScriptExecutorFactory/ShellScriptExecutorFactory.csproj deleted file mode 100644 index b914956..0000000 --- a/ShellScriptExecutorFactory/ShellScriptExecutorFactory.csproj +++ /dev/null @@ -1,82 +0,0 @@ - - - - {4700690A-2D29-40A0-86AC-E5A9F71A479A} - Debug - AnyCPU - Library - Sun.OpenConnectors.Common.Script.Shell - Shell.ScriptExecutorFactory - ShellScriptExecutorFactory - v3.5 - - - prompt - 4 - AnyCPU - bin\Debug\ - True - Full - False - True - DEBUG;TRACE - - - pdbonly - bin\Release\ - prompt - False - 4 - AnyCPU - None - True - False - TRACE - - - - - - 3.5 - - - - 3.5 - - - - - - - - - {F140E8DA-52B4-4159-992A-9DA10EA8EEFB} - Common - - - - - - - diff --git a/ShellScriptExecutorFactory/version.template b/ShellScriptExecutorFactory/version.template deleted file mode 100644 index bd2666a..0000000 --- a/ShellScriptExecutorFactory/version.template +++ /dev/null @@ -1 +0,0 @@ -1.0.0.0 \ No newline at end of file diff --git a/TestBundleV1/AssemblyInfo.cs b/TestBundleV1/AssemblyInfo.cs deleted file mode 100644 index 680a451..0000000 --- a/TestBundleV1/AssemblyInfo.cs +++ /dev/null @@ -1,57 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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]" - * ==================== - */ -#region Using directives - -using System; -using System.Reflection; -using System.Runtime.InteropServices; -using Org.IdentityConnectors.Framework.Spi; -using System.Resources; - -#endregion - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("TestBundleV1")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("TestBundleV1")] -[assembly: AssemblyCopyright("")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// This sets the default COM visibility of types in the assembly to invisible. -// If you need to expose a type to COM, use [ComVisible(true)] on that type. -[assembly: ComVisible(false)] - -// The assembly version has following format : -// -// Major.Minor.Build.Revision -// -// You can specify all the values or you can use the default the Revision and -// Build Numbers by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: NeutralResourcesLanguage("en-US")] - diff --git a/TestBundleV1/Messages.es-ES.resx b/TestBundleV1/Messages.es-ES.resx deleted file mode 100644 index ec894ca..0000000 --- a/TestBundleV1/Messages.es-ES.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tstField.display_es-ES - - - tstField.help_es-ES - - \ No newline at end of file diff --git a/TestBundleV1/Messages.es.resx b/TestBundleV1/Messages.es.resx deleted file mode 100644 index 523473e..0000000 --- a/TestBundleV1/Messages.es.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tstField.help_es - - - tstField.display_es - - \ No newline at end of file diff --git a/TestBundleV1/Messages.resx b/TestBundleV1/Messages.resx deleted file mode 100644 index a988e1e..0000000 --- a/TestBundleV1/Messages.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Help for test field. - - - Display for test field. - - \ No newline at end of file diff --git a/TestBundleV1/TestBundleV1.csproj b/TestBundleV1/TestBundleV1.csproj deleted file mode 100644 index 271ff4e..0000000 --- a/TestBundleV1/TestBundleV1.csproj +++ /dev/null @@ -1,91 +0,0 @@ - - - - {0BC2A013-56FE-46DD-90FC-2D2D57748FB6} - Debug - AnyCPU - Library - TestBundleV1 - TestBundleV1.Connector - v3.5 - OnBuildSuccess - - - prompt - 4 - AnyCPU - bin\Debug\ - True - Full - False - True - DEBUG;TRACE - - - pdbonly - bin\Release\ - TRACE - prompt - 4 - AnyCPU - False - True - False - - - - - - - - - - - - - - Designer - - - Designer - - - Designer - - - - - {F140E8DA-52B4-4159-992A-9DA10EA8EEFB} - Common - - - {8B24461B-456A-4032-89A1-CD418F7B5B62} - Framework - - - - - - - diff --git a/TestBundleV1/TestConnector.cs b/TestBundleV1/TestConnector.cs deleted file mode 100644 index 21fbbc8..0000000 --- a/TestBundleV1/TestConnector.cs +++ /dev/null @@ -1,248 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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; -using System.Threading; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Common.Pooling; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Common.Objects.Filters; -using Org.IdentityConnectors.Framework.Common.Exceptions; -using Org.IdentityConnectors.Framework.Spi; -using Org.IdentityConnectors.Framework.Spi.Operations; -namespace org.identityconnectors.testconnector -{ - public class TstConnectorConfig : AbstractConfiguration - { - /// - /// keep lower case for consistent unit tests - /// - [ConfigurationProperty(OperationTypes = new Type[] { typeof(SyncOp) })] - public string tstField { get; set; } - - /// - /// keep lower case for consistent unit tests - /// - public int numResults { get; set; } - - /// - /// keep lower case for consistent unit tests - /// - public bool failValidation { get; set; } - - /// - /// keep lower case for consistent unit tests - /// - public bool resetConnectionCount { get; set; } - - public override void Validate() - { - if (failValidation) - { - throw new ConnectorException("validation failed " + CultureInfo.CurrentUICulture.TwoLetterISOLanguageName); - } - } - - } - - public class MyTstConnection - { - private readonly int _connectionNumber; - private bool _isGood = true; - - public MyTstConnection(int connectionNumber) - { - _connectionNumber = connectionNumber; - } - - public void Test() - { - if (!_isGood) - { - throw new ConnectorException("Connection is bad"); - } - } - - public void Dispose() - { - _isGood = false; - } - - public bool IsGood() - { - return _isGood; - } - - public int GetConnectionNumber() - { - return _connectionNumber; - } - } - - [ConnectorClass("TestConnector", - typeof(TstConnectorConfig), - MessageCatalogPaths = new String[] { "TestBundleV1.Messages" } - )] - public class TstConnector : CreateOp, PoolableConnector, SchemaOp, SearchOp, SyncOp - { - private static int _connectionCount = 0; - private MyTstConnection _myConnection; - private TstConnectorConfig _config; - - public Uid Create(ObjectClass oclass, ICollection attrs, OperationOptions options) - { - int? delay = (int?)CollectionUtil.GetValue(options.Options, "delay", null); - if (delay != null) - { - Thread.Sleep((int)delay); - } - - if (options.Options.ContainsKey("testPooling")) - { - return new Uid(_myConnection.GetConnectionNumber().ToString()); - } - else - { - String version = "1.0"; - return new Uid(version); - } - } - public void Init(Configuration cfg) - { - _config = (TstConnectorConfig)cfg; - if (_config.resetConnectionCount) - { - _connectionCount = 0; - } - _myConnection = new MyTstConnection(_connectionCount++); - } - - public static String getVersion() - { - return "1.0"; - } - - public void Dispose() - { - if (_myConnection != null) - { - _myConnection.Dispose(); - _myConnection = null; - } - } - - /// - /// Used by the script tests - /// - public String concat(String s1, String s2) - { - return s1 + s2; - } - - public void CheckAlive() - { - _myConnection.Test(); - } - - private class MyTranslator : AbstractFilterTranslator - { - - } - public FilterTranslator CreateFilterTranslator(ObjectClass oclass, OperationOptions options) - { - return new MyTranslator(); - } - public void ExecuteQuery(ObjectClass oclass, String query, ResultsHandler handler, OperationOptions options) - { - - for (int i = 0; i < _config.numResults; i++) - { - int? delay = (int?)CollectionUtil.GetValue(options.Options, "delay", null); - if (delay != null) - { - Thread.Sleep((int)delay); - } - ConnectorObjectBuilder builder = - new ConnectorObjectBuilder(); - builder.SetUid("" + i); - builder.SetName(i.ToString()); - builder.ObjectClass = oclass; - for (int j = 0; j < 50; j++) - { - builder.AddAttribute("myattribute" + j, "myvaluevaluevalue" + j); - } - ConnectorObject rv = builder.Build(); - if (!handler(rv)) - { - break; - } - } - } - public void Sync(ObjectClass objClass, SyncToken token, - SyncResultsHandler handler, - OperationOptions options) - { - for (int i = 0; i < _config.numResults; i++) - { - ConnectorObjectBuilder obuilder = - new ConnectorObjectBuilder(); - obuilder.SetUid(i.ToString()); - obuilder.SetName(i.ToString()); - obuilder.ObjectClass = (objClass); - - SyncDeltaBuilder builder = - new SyncDeltaBuilder(); - builder.Object = (obuilder.Build()); - builder.DeltaType = (SyncDeltaType.CREATE_OR_UPDATE); - builder.Token = (new SyncToken("mytoken")); - SyncDelta rv = builder.Build(); - if (!handler(rv)) - { - break; - } - } - } - - public SyncToken GetLatestSyncToken(ObjectClass objectClass) - { - return new SyncToken("mylatest"); - } - - public Schema Schema() - { - SchemaBuilder builder = new SchemaBuilder(SafeType.Get()); - for (int i = 0; i < 2; i++) - { - ObjectClassInfoBuilder classBuilder = new ObjectClassInfoBuilder(); - classBuilder.ObjectType = ("class" + i); - for (int j = 0; j < 200; j++) - { - classBuilder.AddAttributeInfo(ConnectorAttributeInfoBuilder.Build("attributename" + j, typeof(String))); - } - builder.DefineObjectClass(classBuilder.Build()); - } - return builder.Build(); - } - } -} diff --git a/TestBundleV2/AssemblyInfo.cs b/TestBundleV2/AssemblyInfo.cs deleted file mode 100644 index f2c39b4..0000000 --- a/TestBundleV2/AssemblyInfo.cs +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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]" - * ==================== - */ -#region Using directives - -using System; -using System.Reflection; -using System.Runtime.InteropServices; -using Org.IdentityConnectors.Framework.Spi; - -#endregion - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("TestBundleV2")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("TestBundleV2")] -[assembly: AssemblyCopyright("")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// This sets the default COM visibility of types in the assembly to invisible. -// If you need to expose a type to COM, use [ComVisible(true)] on that type. -[assembly: ComVisible(false)] - -// The assembly version has following format : -// -// Major.Minor.Build.Revision -// -// You can specify all the values or you can use the default the Revision and -// Build Numbers by using the '*' as shown below: -[assembly: AssemblyVersion("2.0.0.0")] - diff --git a/TestBundleV2/TestBundleV2.csproj b/TestBundleV2/TestBundleV2.csproj deleted file mode 100644 index b2b913e..0000000 --- a/TestBundleV2/TestBundleV2.csproj +++ /dev/null @@ -1,82 +0,0 @@ - - - - {3E737796-3A83-4924-9FF1-DC542F21F59E} - Debug - AnyCPU - Library - TestBundleV2 - TestBundleV2.Connector - v3.5 - OnBuildSuccess - - - prompt - 4 - AnyCPU - bin\Debug\ - True - Full - False - True - DEBUG;TRACE - - - pdbonly - bin\Release\ - TRACE - prompt - 4 - AnyCPU - False - True - False - - - - - - - - - - - - - - - - {F140E8DA-52B4-4159-992A-9DA10EA8EEFB} - Common - - - {8B24461B-456A-4032-89A1-CD418F7B5B62} - Framework - - - - - - - diff --git a/TestBundleV2/TestConnector.cs b/TestBundleV2/TestConnector.cs deleted file mode 100644 index 5b74e5d..0000000 --- a/TestBundleV2/TestConnector.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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; -using Org.IdentityConnectors.Common.Pooling; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Spi; -using Org.IdentityConnectors.Framework.Spi.Operations; -namespace org.identityconnectors.testconnector -{ - public class TstConnectorConfig : AbstractConfiguration - { - public override void Validate() - { - } - } - - [ConnectorClass("TestConnector", - typeof(TstConnectorConfig), - MessageCatalogPaths = new String[] { "TestBundleV2.Messages" } - )] - public class TstConnector : CreateOp, Connector, SchemaOp - { - public Uid Create(ObjectClass oclass, ICollection attrs, OperationOptions options) - { - String version = "2.0"; - return new Uid(version); - } - public void Init(Configuration cfg) - { - } - - public void Dispose() - { - - } - - public Schema Schema() - { - return null; - } - } -} diff --git a/TestCommon/FrameworkInternalBridge.cs b/TestCommon/FrameworkInternalBridge.cs deleted file mode 100644 index 17fca33..0000000 --- a/TestCommon/FrameworkInternalBridge.cs +++ /dev/null @@ -1,62 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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; -using System.Collections.Generic; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Common.Security; -using Org.IdentityConnectors.Framework.Spi; -using Org.IdentityConnectors.Framework.Api.Operations; -using Org.IdentityConnectors.Framework.Spi.Operations; -using Org.IdentityConnectors.Framework.Common.Objects; -namespace Org.IdentityConnectors.Test.Common -{ - 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 SafeType LoadType(String typeName) where T : class - { - - Assembly assembly; - lock (LOCK) - { - if (_assembly == null) - { - AssemblyName assemName = new AssemblyName(); - assemName.Name = "FrameworkInternal"; - _assembly = Assembly.Load(assemName); - } - assembly = _assembly; - } - - return SafeType.ForRawType(assembly.GetType(typeName, true)); - - } - } -} diff --git a/TestCommon/PropertyBag.cs b/TestCommon/PropertyBag.cs deleted file mode 100644 index bcb0ec9..0000000 --- a/TestCommon/PropertyBag.cs +++ /dev/null @@ -1,154 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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; -using Org.IdentityConnectors.Common; - -namespace Org.IdentityConnectors.Test.Common -{ - /// - /// Encapsulates a read-only bag of properties, which can be accessed in a type-safe manner. - /// - /// - /// The simplest way to obtain a required (i.e., the property must be in the bag, otherwise an exception is thrown) - /// property value is . - /// If the property is not a required one, the method can be used, - /// which also takes a default value which is returned when the property is not present in the bag. - /// - public sealed class PropertyBag - { - #region Member variables - private readonly Dictionary _bag; - #endregion - - #region Constructors - /// - /// Initializes a new instance of the class with the properties. - /// - /// The properties contained in the bag. - internal PropertyBag(IDictionary bag) - { - _bag = new Dictionary(bag); - } - #endregion - - #region Methods - /// - /// Gets the value of a required property defined by in a type-safe manner. - /// - /// The type of the property to get. - /// The name of the property. - /// The value of the property in bag; the value might be null. - /// Thrown when no property found defined by - /// Thrown when the property exists, but its value is not of type . - /// See for details on the types that can be defined in . - public T GetProperty(string name) - { - if (!_bag.ContainsKey(name)) - { - throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, @"Property named ""{0}"" not found in bag.", name)); - } - - return CastValue(name); - } - - /// - /// Casts the value of a property defined by to the type . - /// - /// The type, the property must be cast to. - /// The name of the property. - /// The value of the property in bag cast to type ; the value might be null. - /// Thrown when the value of the property is not of type . - /// The property must be in the bag! - /// - /// The .Net BCL does not provide wrappers for primitive classes, hence to make sure that a property containing a null value - /// cannot break your code use a nullable primitive type. - /// For example: - /// - /// PropertyBag bag = TestHelpers.GetProperties(typeof(yourConnector)); - /// int? mightBeNull = bag.GetProperty("property name"); - /// - /// - /// - /// - private T CastValue(string name) - { - object value = _bag[name]; - - //if the value of the property is null then just return null, there is no need for type checking - if ((value != null) && - !(value is T)) //otherwise check if value is an instance of T - { - throw new InvalidCastException(string.Format(CultureInfo.InvariantCulture, - @"Property named ""{0}"" is of type ""{1}"" but expected type was ""{2}""", - name, value.GetType(), typeof (T))); - } - - return (T)value; - } - - /// - /// Gets a property value, returning a default value when no property with the specified name exists in the bag. - /// - /// The type of the property to get. - /// The name of the property. - /// The default value returned when no property with the specified name exists in the bag. - /// The value of the property in bag cast to type or the default value ; - /// the value might be null. - /// Thrown when the property exists, but its value is not of type . - /// See for details on the types that can be defined in . - public T GetProperty(string name, T def) - { - if (!_bag.ContainsKey(name)) - { - return def; - } - return CastValue(name); - } - - /// - /// Gets a required property value known to be of type . - /// - /// The name of the property. - /// The value of the property in bag; the value might be null. - /// Thrown when no property found defined by - /// Thrown when the property exists, but its value is not of type . - /// The method expects that the value is an instance of . It does not attempt to - /// call on the value. - public string GetStringProperty(string name) - { - return GetProperty(name); - } - - /// - /// Returns a key-value pair collection that represents the current . - /// - /// A instance that represents the current . - internal IDictionary ToDictionary() - { - return CollectionUtil.NewDictionary(_bag); - } - #endregion - } -} diff --git a/TestCommon/Test.cs b/TestCommon/Test.cs deleted file mode 100644 index ee506f5..0000000 --- a/TestCommon/Test.cs +++ /dev/null @@ -1,529 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Xml; -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Framework.Api; -using Org.IdentityConnectors.Framework.Api.Operations; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Common.Objects.Filters; -using Org.IdentityConnectors.Framework.Spi; -using Org.IdentityConnectors.Framework.Spi.Operations; -using Org.IdentityConnectors.Test.Common.Spi; -using System.Globalization; -using System.Xml.Schema; - -namespace Org.IdentityConnectors.Test.Common -{ - /// - /// which stores all connector objects into - /// list retrievable with . - /// - public sealed class ToListResultsHandler - { - private IList _objects - = new List(); - public bool Handle(ConnectorObject obj) - { - _objects.Add(obj); - return true; - } - - public IList Objects - { - get - { - return _objects; - } - } - } - - /// - /// Bag of utility methods useful to connector tests. - /// - public sealed class TestHelpers - { - - private TestHelpers() - { - } - - /// - /// Method for convenient testing of local connectors. - /// - public static APIConfiguration CreateTestConfiguration(SafeType clazz, - Configuration config) - { - return GetSpi().CreateTestConfiguration(clazz, config); - } - - /// - /// Fills a configuration bean with data from the given map. - /// - /// - /// The map - /// keys are configuration property names and the values are - /// configuration property values. - /// - /// the configuration bean. - /// the map with configuration data. - public static void FillConfiguration(Configuration config, - IDictionary configData) - { - GetSpi().FillConfiguration(config, configData); - } - - /// - /// Creates an dummy message catalog ideal for unit testing. - /// - /// - /// All messages are formatted as follows: - /// - /// message-key: arg0.toString(), ..., argn.toString - /// - /// - /// A dummy message catalog. - public static ConnectorMessages CreateDummyMessages() - { - return GetSpi().CreateDummyMessages(); - } - - public static IList SearchToList(SearchApiOp search, - ObjectClass oclass, - Filter filter) - { - return SearchToList(search, oclass, filter, null); - } - - public static IList SearchToList(SearchApiOp search, - ObjectClass oclass, - Filter filter, - OperationOptions options) - { - ToListResultsHandler handler = new - ToListResultsHandler(); - search.Search(oclass, filter, handler.Handle, options); - return handler.Objects; - } - /// - /// Performs a raw, unfiltered search at the SPI level, - /// eliminating duplicates from the result set. - /// - /// The search SPI - /// The object class - passed through to - /// connector so it may be null if the connecor - /// allowing it to be null. (This is convenient for - /// unit tests, but will not be the case in general) - /// The filter to search on - /// The options - may be null - will - /// be cast to an empty OperationOptions - /// The list of results. - public static IList SearchToList(SearchOp search, - ObjectClass oclass, - Filter filter) where T : class - { - return SearchToList(search, oclass, filter, null); - } - /// - /// Performs a raw, unfiltered search at the SPI level, - /// eliminating duplicates from the result set. - /// - /// The search SPI - /// The object class - passed through to - /// connector so it may be null if the connecor - /// allowing it to be null. (This is convenient for - /// unit tests, but will not be the case in general) - /// The filter to search on - /// The options - may be null - will - /// be cast to an empty OperationOptions - /// The list of results. - public static IList SearchToList(SearchOp search, - ObjectClass oclass, - Filter filter, - OperationOptions options) where T : class - { - ToListResultsHandler handler = new - ToListResultsHandler(); - Search(search, oclass, filter, handler.Handle, options); - return handler.Objects; - } - - /// - /// Performs a raw, unfiltered search at the SPI level, - /// eliminating duplicates from the result set. - /// - /// The search SPI - /// The object class - passed through to - /// connector so it may be null if the connecor - /// allowing it to be null. (This is convenient for - /// unit tests, but will not be the case in general) - /// The filter to search on - /// The result handler - /// The options - may be null - will - /// be cast to an empty OperationOptions - public static void Search(SearchOp search, - ObjectClass oclass, - Filter filter, - ResultsHandler handler, - OperationOptions options) where T : class - { - GetSpi().Search(search, oclass, filter, handler, options); - } - - //At some point we might make this pluggable, but for now, hard-code - private const String IMPL_NAME = - "Org.IdentityConnectors.Framework.Impl.Test.TestHelpersImpl"; - private static readonly object LOCK = new object(); - private static TestHelpersSpi _instance; - - /// - /// Returns the instance of this factory. - /// - /// The instance of this factory - private static TestHelpersSpi GetSpi() - { - lock (LOCK) - { - if (_instance == null) - { - SafeType type = FrameworkInternalBridge.LoadType(IMPL_NAME); - _instance = type.CreateInstance(); - } - return _instance; - } - } - - private static Dictionary _propertyBags = new Dictionary(); - private const string ConfigFileName = "config.xml"; - private static readonly object ConfigurationLock = new object(); - private const string LoadConfigErrorMessage = @"TestHelpers: Unable to load optional XML configuration file ""{0}"". Exception: {1}"; - - /// - /// The name of the environment variable that contains the name of a certain configuration from which the - /// test configuration properties to be loaded besides the general properties. - /// - internal const string TestConfigEVName = "TEST_CONFIG"; - - /// - /// The name of the environment variable that contains the path of the root directory to the private configurations. - /// - internal const string PrivateConfigRootEVName = "PRIVATE_CONFIG_ROOT"; - - /// - /// The name of the environment variable, the value of which is the location of the current user's profile directory. - /// - internal const string UserProfileEVName = "USERPROFILE"; - - /// - /// Gets the configuration properties for a specified type. - /// - /// - /// - /// Gets the configuration properties for the specified from the provided . - /// - /// The type, the fully qualified name (FQN) of which to be used to identify the configuration. - /// The assembly, that contains the public configuration properties. Recommended to be the test project. - /// Bag of properties for the specified and optionally set configuration. - /// The properties are loaded from public and private configuration files, the former as manifest resources, the - /// latter as file system entries by using the specified as root prefix. Optionally, a certain test setup - /// can be used by defining the "TEST_CONFIG" environment variable that can be used to override the general configuration properties. Both - /// public and private configurations can be overridden with a certain test setup. - /// - /// Public configuration properties are loaded as manifest resources from the specified according - /// to the following: - /// - /// - /// Load the general properties from a resource, the name of which is constructed as follows: - /// type.FullName + ".config.config.xml". To achieve this, you need to create a new folder - /// in your test project named as the FQN of the specified , then create a folder called - /// "config", at last add the configuration file called "config.xml" to this folder and set its "Build Action" - /// property to "Embedded Resource". - /// - /// - /// - /// Load the configuration specific properties from a resource, the name of which is constructed - /// as follows: - /// type.FullName + ".config."+ Environment.GetEnvironmentVariable("TEST_CONFIG") + ".config.xml". - /// To achieve this, you need to create a new folder underneath the previously created "config" folder, its name - /// is defined by the configuration name and add the "config.xml" to this particular folder with "Build Action" - /// property set to "Embedded Resource". - /// - /// - /// - /// - /// - /// The private configuration properties are loaded from the file system as follows: - /// - /// - /// Load the general properties from a file, the path of which is constructed as follows: - /// Environment.GetEnvironmentVariable("PRIVATE_CONFIG_ROOT") + "\config\" + type.FullName + "\config-private\config.xml" - /// - /// - /// - /// Load the configuration specific properties from a file, the path of which is constructed as follows: - /// Environment.GetEnvironmentVariable("PRIVATE_CONFIG_ROOT") + "\config\" + type.FullName + "\config-private\" + - /// Environment.GetEnvironmentVariable("TEST_CONFIG") + "\config.xml" - /// - /// - /// - /// NOTE that if the "PRIVATE_CONFIG_ROOT" environment variable is not defined, it will be replaced in the path with the default root - /// which points to a directory of the current user's profile container, the path of which is constructed as follows: - /// Environment.GetEnvironmentVariable("USERPROFILE") + "\.connectors\" + type.Assembly.GetName().Name - /// For example: c:\Users\Administrator\.connectors\CONNECTOR_CONTAINER_ASSEMBLY_NAME\ - /// - /// - /// Thrown when the root directory of the private configuration cannot be determined. - public static PropertyBag GetProperties(Type type, Assembly assembly) - { - lock (ConfigurationLock) - { - PropertyBag bag; - if (_propertyBags.ContainsKey(type.FullName)) - { - bag = _propertyBags[type.FullName]; - } - else - { - bag = LoadProperties(type, assembly); - _propertyBags.Add(type.FullName, bag); - } - return bag; - } - } - - /// - /// Gets the configuration properties for the specified from the calling assembly. - /// - /// The type, the fully qualified name (FQN) of which to be used to identify the configuration. - /// Bag of properties for the specified and optionally set configuration. - /// See for details of the property loading mechanism. - public static PropertyBag GetProperties(Type type) - { - return GetProperties(type, Assembly.GetCallingAssembly()); - } - - /// - /// Loads the properties from public and private configurations, optionally from a certain configuration defined by - /// "TEST_CONFIG" environment variable. - /// - /// The type, the fully qualified name (FQN) of which to be used to identify the configuration. - /// The assembly, that contains the configuration resources. - /// Bag of properties for the specified . - /// Thrown when the root directory of the private configuration cannot be determined. - private static PropertyBag LoadProperties(Type type, Assembly assembly) - { - string bagName = type.FullName; - string configFilePath = string.Empty; - IDictionary properties = null; - var ret = new Dictionary(); - - //load the general public properties file - configFilePath = string.Format(CultureInfo.InvariantCulture, "{0}.config.{1}", bagName, ConfigFileName); - properties = LoadConfigurationFromResource(assembly, configFilePath); - CollectionUtil.AddOrReplaceAll(ret, properties); - - //load the configuration specific public properties file - string configurationName = Environment.GetEnvironmentVariable(TestConfigEVName); - if (!StringUtil.IsBlank(configurationName)) - { - configFilePath = string.Format(CultureInfo.InvariantCulture, "{0}.config.{1}.{2}", bagName, - configurationName, ConfigFileName); - properties = LoadConfigurationFromResource(assembly, configFilePath); - CollectionUtil.AddOrReplaceAll(ret, properties); - } - - //determine the root directory of the private properties files - string privateConfigRoot = string.Empty; - if (Environment.GetEnvironmentVariable(PrivateConfigRootEVName) != null) - { - privateConfigRoot = Environment.GetEnvironmentVariable(PrivateConfigRootEVName); - } - else - { - if (Environment.GetEnvironmentVariable(UserProfileEVName) != null) - { - privateConfigRoot = Path.Combine(Environment.GetEnvironmentVariable(UserProfileEVName), - Path.Combine(".connectors", type.Assembly.GetName().Name)); - } - else - throw new InvalidOperationException( - @"Neither the ""PRIVATE_CONFIG_ROOT"" nor the ""USERPROFILE"" environment variable is defined."); - } - - privateConfigRoot = Path.Combine(privateConfigRoot, "config"); - - //load the general private properties file - configFilePath = Path.Combine(Path.Combine(Path.Combine(privateConfigRoot, bagName), "config-private"), ConfigFileName); - properties = LoadConfigurationFromFile(configFilePath); - CollectionUtil.AddOrReplaceAll(ret, properties); - - // load the configuration specific private properties file - if (!StringUtil.IsBlank(configurationName)) - { - configFilePath = Path.Combine(Path.Combine(Path.Combine(Path.Combine(privateConfigRoot, bagName), - "config-private"), configurationName), ConfigFileName); - properties = LoadConfigurationFromFile(configFilePath); - CollectionUtil.AddOrReplaceAll(ret, properties); - } - return new PropertyBag(ret); - } - - /// - /// Loads the configuration properties from the specified . - /// - /// The config file path. - /// A property name-value pair collection representing the configuration. - private static IDictionary LoadConfigurationFromFile(string filePath) - { - IDictionary properties = null; - try - { - if (File.Exists(filePath)) - { - using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - properties = ReadConfiguration(stream); - } - } - else - { - Trace.TraceWarning(@"The configuration file on path ""{0}"" is not found.", filePath); - } - } - catch (Exception e) - { - Trace.TraceInformation(LoadConfigErrorMessage, filePath, e); - } - return properties; - } - - /// - /// Loads the configuration properties from a resource defined by . - /// - /// The assembly, that contains the resource. - /// The name of the resource. - /// A property name-value pair collection representing the configuration. - private static IDictionary LoadConfigurationFromResource(Assembly assembly, string configResName) - { - IDictionary properties = null; - try - { - //the default namespace with which the resource name starts is not known, therefore - //it must be looked up in the manifest resource list - var resourceName = (from name in assembly.GetManifestResourceNames() - where name.EndsWith(configResName, StringComparison.InvariantCultureIgnoreCase) - select name).FirstOrDefault(); - if (!StringUtil.IsBlank(resourceName)) - { - using (var stream = assembly.GetManifestResourceStream(resourceName)) - { - if (stream == null) - { - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, - @"Although, the configuration file called ""{0}"" exists, it cannot be accessed.", - configResName)); - } - properties = ReadConfiguration(stream); - } - } - else - { - Trace.TraceWarning(@"The configuration resource called ""{0}"" is not found.", configResName); - } - } - catch (Exception e) - { - Trace.TraceInformation(LoadConfigErrorMessage, configResName, e); - } - return properties; - } - - /// - /// Reads the configuration properties from the provided stream. - /// - /// The stream containing the configuration properties. - /// A property name-value pair collection representing the configuration. - /// The configuration properties are stored in XML format. The stream, that is opened for reading or it can be read, - /// has to contain the configuration properties in XML that adheres to the config.xsd schema embedded to - /// the assembly of this project. - /// - /// For example: - /// - /// - /// - /// - /// ]]> - /// - /// - /// Thrown when the XSD used for validating the configuration is not found in the manifest. - /// Thrown when the contains XML that does not adhere to the schema. - internal static IDictionary ReadConfiguration(Stream configStream) - { - var properties = new Dictionary(); - //validate the XML configuration against the XSD - var schemaSet = new XmlSchemaSet(); - var schemaStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Org.IdentityConnectors.Test.Common.config.xsd"); - if (schemaStream == null) - { - throw new InvalidOperationException(@"The schema used for validating of the configuration file is not found."); - } - var schemaReader = XmlReader.Create(schemaStream); - schemaSet.Add(null, schemaReader); - - //load the reader with the data stream and ignore all white space nodes - var readerSettings = new XmlReaderSettings - { - IgnoreWhitespace = true, - ValidationType = ValidationType.Schema, - Schemas = schemaSet - }; - - using (var reader = XmlReader.Create(configStream, readerSettings)) - { - //read all the nodes and extract the ones that contain properties - while (reader.Read()) - { - if (reader.NodeType == XmlNodeType.Element && - reader.Name.Equals("property")) - { - string name = reader.GetAttribute("name"); - string xmlValue = reader.GetAttribute("value"); - if (!StringUtil.IsBlank(name) && xmlValue != null) - { - properties[name] = xmlValue; - } - } - } - } - return properties; - } - } -} diff --git a/TestCommon/TestCommon.csproj b/TestCommon/TestCommon.csproj deleted file mode 100644 index 1abcaa6..0000000 --- a/TestCommon/TestCommon.csproj +++ /dev/null @@ -1,69 +0,0 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {E6A207D2-E083-41BF-B522-D9D3EC09323E} - Library - Properties - Org.IdentityConnectors.Test.Common - TestCommon - v3.5 - 512 - FrameworkTests - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - 3.5 - - - 3.5 - - - 3.5 - - - - - - - - - - - - - - {F140E8DA-52B4-4159-992A-9DA10EA8EEFB} - Common - - - {8B24461B-456A-4032-89A1-CD418F7B5B62} - Framework - - - - - - \ No newline at end of file diff --git a/TestCommon/TestHelpersSpi.cs b/TestCommon/TestHelpersSpi.cs deleted file mode 100644 index c618dc5..0000000 --- a/TestCommon/TestHelpersSpi.cs +++ /dev/null @@ -1,54 +0,0 @@ -/* - * ==================== - * 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://IdentityConnectors.dev.java.net/legal/license.txt - * 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 identityconnectors/legal/license.txt. - * 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.Collections.Generic; - -using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Framework.Api; -using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Framework.Common.Objects.Filters; -using Org.IdentityConnectors.Framework.Spi; -using Org.IdentityConnectors.Framework.Spi.Operations; - -namespace Org.IdentityConnectors.Test.Common.Spi -{ - /// - /// Private use only, do not implement! Use the methods in - /// instead. - /// - public interface TestHelpersSpi - { - APIConfiguration CreateTestConfiguration(SafeType clazz, - Configuration config); - - void FillConfiguration(Configuration config, - IDictionary configData); - - void Search(SearchOp search, - ObjectClass oclass, - Filter filter, - ResultsHandler handler, - OperationOptions options) where T : class; - - ConnectorMessages CreateDummyMessages(); - } -} diff --git a/TestCommon/config.xsd b/TestCommon/config.xsd deleted file mode 100644 index 968ccb7..0000000 --- a/TestCommon/config.xsd +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/TestCommon/version.template b/TestCommon/version.template deleted file mode 100644 index db70057..0000000 --- a/TestCommon/version.template +++ /dev/null @@ -1 +0,0 @@ -1.2.0.0 diff --git a/server.pfx b/server.pfx deleted file mode 100644 index 63f632a287bcbab06114bdde513c6b95c616be6d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1704 zcmY+Dc|6p47{`Aze*K1Q>@-RyjO5G?zsZ=HZN$hmMvf#`VMnfF4I$Tr#^#7D8sr|i z!V*e!IEzZDSSqvFvTg2;DNWL>{pr>2zV?sr^L?K8b9}#lJRg_`RiaT+Fc10xlG%~W zOcrlIVNe1dv=8J#b_lkCc~UL^OG#CLJgG7S7a=DflKtBC&3Y7Cz(ZewdFU2c8Cw4j zMuy9Q(yVc-fI8yT5E_kn1oF^Xbc#*1_s~A#@Ol4_{1b&gn@69;7rhl%cs$Nj91|Kl z&TeB+#~Ww+*jjI791dETOOBQ%BpL`0izlv+uW}8P0`+5(%UaPj6tfZ!?ScG&=PTJt z4ilYGH@7wP@sv}U^eg%ANA)I!qjVtOKy;3(`;vGab2$=t;J<@V?%Q9`ROFi_(#8t>&7 zoL3VNq~t7X0p}s>Y*Tg6`r|KBrdh+Fa@}bY{)0lp)s=Ow5(8HwGYok~CQoUfkF1DzRsa3I~Ea1Ek110bF;u_mz`&iFgr;+$nIZBc^HY!jcj5?7v@uP$E zjz^!n3+}a>-mSurz(Gsq$vUrm7K3s~?Q|BV*i4R_y4$<<$rNL>xfsAph$YLFg3Y5n z$@_E%bmSDaEo~g@Y3@@_YWAR>CYHJNvQgN##9`{Rk%f|Fr@Yk%*>F1`tfyY z!0~4o8lJ>{nVvC^{`6dxN*bg6YD|Z~Tf-@+YT3fPG2u?f;koDT{7v>@Cx*LC$t9U` zHkZ0ru*7OWqGd&7RqdZJxxrEZ|a{ zmsjQ$D~B3S+FG^lnay2Th%8qis4&?n+gtTdY9Ig5mD>Bw2+d|=g|7@=Y4LOZe!eE@ z__Yx z2>}9-$Q^;Vyp)})%qLo>_lTW-sup11OqYu+0e@2O3XPH)_YcN*zs%jTl> z&SmIaT!|Y#dfR%Yf=)5>n#b6_FRAC+Wd~^xo@IoncI?%0$=UsW^ATG{6mRk}&G)sy zygKvck-{ldNA=6t%T`hBqLQvMpIv)z4i`18f*)_y=iX-ztb{S%Q54|raojntLp6!f z2H@SzwIf$s-M94;tSTdadCoE5+!PwZLOvz%%#Ju|@}TI$L^R=YeG{Sy{P zx3_QMrT=z4HP}&iB&5=b0?XMgblcM&Hk}RBoQ{8bQJB<@7 zNRPa>_?}nf-Vc4X_uaB{et5==kTHuCL`+8Kk$}ig@8(@`62?G&@%0OpF@4rdQNEF_ zmXV`*-{kxFok=R+`c3^lm&CM`xMmomKI|6I$lN7cZQ8oNcu8O&`IF_43J! zrvv1`;DGt|ycVC7Snc|IH4Y%vHB{QHZ6?TWIjf_>9URCMZK)H@&HQyWY#yr>ACFeg zm~UJ-l!?_|6uC8I75=r Date: Fri, 13 Nov 2009 14:54:13 +0000 Subject: [PATCH 02/33] Issue 593: Move framework to a single directory - .NET part --- build.xml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/build.xml b/build.xml index 00dbfae..c17d882 100644 --- a/build.xml +++ b/build.xml @@ -23,8 +23,6 @@ - - @@ -33,21 +31,29 @@ - + + + + + - + + + + + @@ -78,4 +84,3 @@ - From bf37e1e37518d329b867380e2d55857f2cd63e68 Mon Sep 17 00:00:00 2001 From: abadea Date: Fri, 13 Nov 2009 17:16:19 +0000 Subject: [PATCH 03/33] Issue 593: Move framework to a single directory - Java part --- ActiveDirectoryConnector/build.xml | 2 +- ExchangeConnector/build.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ActiveDirectoryConnector/build.xml b/ActiveDirectoryConnector/build.xml index 54c99e4..1e98d75 100644 --- a/ActiveDirectoryConnector/build.xml +++ b/ActiveDirectoryConnector/build.xml @@ -22,7 +22,7 @@ --> - + diff --git a/ExchangeConnector/build.xml b/ExchangeConnector/build.xml index 3c4eba4..fa50e66 100644 --- a/ExchangeConnector/build.xml +++ b/ExchangeConnector/build.xml @@ -22,7 +22,7 @@ --> - + From 6728c422fd09a2a39aa683313a43fa742ad6fb13 Mon Sep 17 00:00:00 2001 From: roman_kitko Date: Mon, 14 Dec 2009 10:07:30 +0000 Subject: [PATCH 04/33] Use 'Last changed Rev' for revision part of version in dotnet builds. This will be in sync with java builds --- DotNetCommonBuild.Targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DotNetCommonBuild.Targets b/DotNetCommonBuild.Targets index df2777f..ff4eac8 100644 --- a/DotNetCommonBuild.Targets +++ b/DotNetCommonBuild.Targets @@ -32,7 +32,7 @@ - + From 2602056e3af6deaa5706d915e81be659488f7673 Mon Sep 17 00:00:00 2001 From: lajos_nagy Date: Thu, 17 Dec 2009 11:25:23 +0000 Subject: [PATCH 05/33] Issue 606: Test operation fails with bad error message when period is used To check for syntax errors in a dn the ADSI lib is used by creating a PathnameClass out of the text representation of the dn. Added new exception with a friendly error message if the existence check of the Container config. prop. throws an exception. Configuration validation has been added to the initialization sequence of the connector, hence any time a new instance of the connector is created and initialized the configuration will be validated. Configuration related unit tests have been moved to ActiveDirectoryConfigurationTests to separate from connector tests. --- .../ActiveDirectoryConfiguration.cs | 44 +++-- .../ActiveDirectoryConnector.cs | 43 ++--- .../ActiveDirectoryUtils.cs | 34 ++++ ActiveDirectoryConnector/Messages.resx | 9 + .../ActiveDirectoryConfigurationTests.cs | 173 +++++++++++++++++ .../ActiveDirectoryConnectorTest.cs | 182 ++++++++---------- .../ActiveDirectoryConnectorTests.csproj | 5 +- ActiveDirectoryConnectorTests/ConfigHelper.cs | 92 +++++++++ 8 files changed, 441 insertions(+), 141 deletions(-) create mode 100644 ActiveDirectoryConnectorTests/ActiveDirectoryConfigurationTests.cs create mode 100644 ActiveDirectoryConnectorTests/ConfigHelper.cs diff --git a/ActiveDirectoryConnector/ActiveDirectoryConfiguration.cs b/ActiveDirectoryConnector/ActiveDirectoryConfiguration.cs index 6fa201d..444c41c 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryConfiguration.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryConfiguration.cs @@ -104,50 +104,68 @@ public ActiveDirectoryConfiguration() LDAPHostName = ""; } + /// + /// Determines if the configuration is valid. + /// + /// See for the definition of a valid + /// configuration. + /// + /// Thrown when the configuration is not valid. public override void Validate() { - String message = "Configuration errors: "; + var message = new StringBuilder(); + Boolean foundError = false; // can't lookup the schema without the domain name if ((DomainName == null) || (DomainName.Length == 0)) { - message += ConnectorMessages.Format( - "confReqParam_domainName", "Domain name not supplied "); + message.Append(ConnectorMessages.Format( + "confReqParam_domainName", "Domain name not supplied ")); foundError = true; } if ((DirectoryAdminName == null) || (DirectoryAdminName.Length == 0)) { - message += ConnectorMessages.Format( - "confReqParam_adminName", "Directory administrator name not supplied "); + message.Append(ConnectorMessages.Format( + "confReqParam_adminName", "Directory administrator name not supplied ")); foundError = true; } if ((DirectoryAdminPassword == null) || (DirectoryAdminPassword.Length == 0)) { - message += ConnectorMessages.Format( - "confReqParam_adminPass", "Directory administrator password not supplied "); + message.Append(ConnectorMessages.Format( + "confReqParam_adminPass", "Directory administrator password not supplied ")); foundError = true; } if ((ObjectClass == null) || (ObjectClass.Length == 0)) { - message += ConnectorMessages.Format( - "confReqParam_objClass", "ObjectClass was not supplied "); + message.Append(ConnectorMessages.Format( + "confReqParam_objClass", "ObjectClass was not supplied ")); foundError = true; } - if ((Container == null) || (Container.Length == 0)) + if (string.IsNullOrEmpty(Container)) { - message += ConnectorMessages.Format( - "confReqParam_Container", "Container was not supplied "); + message.Append(ConnectorMessages.Format( + "confReqParam_Container", "Container was not supplied ")); foundError = true; } + else + { + if (!ActiveDirectoryUtils.IsValidDn(Container)) + { + message.Append( ConnectorMessages.Format( + "confParam_Container_invalid_path", @"Container '{0}' could not be recognized as a distinguished name (DN) ", Container ) ); + foundError = true; + } + } if (foundError) { - throw new ConfigurationException(message); + throw new ConfigurationException( ConnectorMessages.Format( + "ex_ConfigErrors", "Configuration errors: {0}", message.ToString() ) ); } } } diff --git a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs b/ActiveDirectoryConnector/ActiveDirectoryConnector.cs index dbe5eb1..e97a2ce 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryConnector.cs @@ -37,6 +37,7 @@ using Org.IdentityConnectors.Framework.Common; using System.Text; using Org.IdentityConnectors.Common.Script; +using System.Globalization; namespace Org.IdentityConnectors.ActiveDirectory { @@ -246,6 +247,7 @@ public virtual Uid Create(ObjectClass oclass, public virtual void Init(Configuration configuration) { Trace.TraceInformation("Active Directory Init method"); + configuration.Validate(); _configuration = (ActiveDirectoryConfiguration)configuration; _utils = new ActiveDirectoryUtils(_configuration); } @@ -678,12 +680,6 @@ private void ExecuteQuery(ObjectClass oclass, string query, } } } - - // this is the path that all searches come from unless otherwise directed - private string GetSearchContainerPath() - { - return GetSearchContainerPath(UseGlobalCatalog(), _configuration.LDAPHostName, _configuration.Container); - } private string GetSearchContainerPath(bool useGC, string hostname, string searchContainer) { @@ -759,26 +755,29 @@ public virtual void Test() _configuration.ObjectClass)); } - // see if SearchContainer is valid - if (!DirectoryEntry.Exists(GetSearchContainerPath())) + try { - throw new ConnectorException( - _configuration.ConnectorMessages.Format( - "ex_InvalidSearchContainerInConfiguration", - "An invalid search container was supplied: {0}", - _configuration.Container)); + // see if the Container exists + if (!DirectoryEntry.Exists( GetSearchContainerPath( UseGlobalCatalog(), + _configuration.LDAPHostName, _configuration.Container ) )) + { + throw new ConnectorException( + _configuration.ConnectorMessages.Format( + "ex_InvalidContainerInConfiguration", + "An invalid container was supplied: {0}", + _configuration.Container ) ); + } } - - // see if the Context exists - - if (!DirectoryEntry.Exists(GetSearchContainerPath(UseGlobalCatalog(), - _configuration.LDAPHostName, _configuration.Container))) + catch (DirectoryServicesCOMException dscex) { + Trace.TraceError( string.Format( CultureInfo.InvariantCulture, + "Failed to determine whether the Container '{0}' exists. Exception: {1}", _configuration.Container, dscex ) ); + throw new ConnectorException( - _configuration.ConnectorMessages.Format( - "ex_InvalidContainerInConfiguration", - "An invalid container was supplied: {0}", - _configuration.Container)); + _configuration.ConnectorMessages.Format( + "ex_ContainerNotFound", + "Could not find the Container '{0}', the following message was returned from the server: {1}", + _configuration.Container, dscex.Message ), dscex ); } } diff --git a/ActiveDirectoryConnector/ActiveDirectoryUtils.cs b/ActiveDirectoryConnector/ActiveDirectoryUtils.cs index 76eee0f..70ea06e 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryUtils.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryUtils.cs @@ -34,6 +34,7 @@ using ActiveDs; using Org.IdentityConnectors.Common.Security; using System.DirectoryServices.ActiveDirectory; +using System.Runtime.InteropServices; namespace Org.IdentityConnectors.ActiveDirectory { @@ -769,6 +770,39 @@ static internal LargeInteger GetLargeIntegerFromLong(Int64 int64Value) largeInteger.LowPart = (int)(int64Value & 0xFFFFFFFF); return largeInteger; } + + /// + /// Determines whether is a valid distinguished name. + /// + /// The string representation of the distinguished name to validate. + /// + /// true if is valid; otherwise, false. + /// + /// A DN is valid if it can be processed by the AD API. This method does not test RFC 2253 compliance, + /// but only basic syntactical check. + internal static bool IsValidDn(string dn) + { + var result = false; + try + { + if (getADSPathname( null, null, dn ) != null) + { + result = true; + } + } + catch (COMException comex) + { + if (comex.ErrorCode == -2147463168) //E_ADS_BAD_PATHNAME + { + result = false; + } + else + { + throw; + } + } + return result; + } } } diff --git a/ActiveDirectoryConnector/Messages.resx b/ActiveDirectoryConnector/Messages.resx index 61cebd2..ab15935 100644 --- a/ActiveDirectoryConnector/Messages.resx +++ b/ActiveDirectoryConnector/Messages.resx @@ -279,4 +279,13 @@ An invalid search context was supplied: {0} + + Container '{0}' could not be recognized as a distinguished name (DN) + + + Configuration errors: {0} + + + Could not find the Container '{0}', the following message was returned from the server: {1} + \ No newline at end of file diff --git a/ActiveDirectoryConnectorTests/ActiveDirectoryConfigurationTests.cs b/ActiveDirectoryConnectorTests/ActiveDirectoryConfigurationTests.cs new file mode 100644 index 0000000..de953c8 --- /dev/null +++ b/ActiveDirectoryConnectorTests/ActiveDirectoryConfigurationTests.cs @@ -0,0 +1,173 @@ +/* + * ==================== + * 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://IdentityConnectors.dev.java.net/legal/license.txt + * 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 identityconnectors/legal/license.txt. + * 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.Linq; +using System.Text; +using NUnit.Framework; +using Org.IdentityConnectors.Test.Common; +using Org.IdentityConnectors.Framework.Common.Exceptions; + +namespace Org.IdentityConnectors.ActiveDirectory +{ + [TestFixture] + public class ActiveDirectoryConfigurationTests + { + [Test] + public void TestProperties() + { + var sut = new ActiveDirectoryConfiguration + { + ConnectorMessages = TestHelpers.CreateDummyMessages() + }; + + var container = TestHelpers.GetProperties( + typeof( ActiveDirectoryConnector ) ).GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ); + sut.Container = container; + Assert.AreEqual( container, sut.Container, "Container" ); + + //test with the negate of the default value + var createHomeDirectory = !sut.CreateHomeDirectory; + sut.CreateHomeDirectory = createHomeDirectory; + Assert.AreEqual( createHomeDirectory, sut.CreateHomeDirectory, "CreateHomeDirectory" ); + + var directoryAdminName = TestHelpers.GetProperties( + typeof( ActiveDirectoryConnector ) ).GetProperty( ConfigHelper.CONFIG_PROPERTY_USER ); + sut.DirectoryAdminName = directoryAdminName; + Assert.AreEqual( directoryAdminName, sut.DirectoryAdminName, "DirectoryAdminName" ); + + var directoryAdminPassword = TestHelpers.GetProperties( + typeof( ActiveDirectoryConnector ) ).GetProperty( ConfigHelper.CONFIG_PROPERTY_PASSWORD ); + sut.DirectoryAdminPassword = directoryAdminPassword; + Assert.AreEqual( directoryAdminPassword, sut.DirectoryAdminPassword, "DirectoryAdminPassword" ); + + var domainName = TestHelpers.GetProperties( + typeof( ActiveDirectoryConnector ) ).GetProperty( ConfigHelper.CONFIG_PROPERTY_DOMAIN_NAME ); + sut.DomainName = domainName; + Assert.AreEqual( domainName, sut.DomainName, "DomainName" ); + + var ldapHostName = TestHelpers.GetProperties( + typeof( ActiveDirectoryConnector ) ).GetProperty( ConfigHelper.CONFIG_PROPERTY_LDAPHOSTNAME ); + sut.LDAPHostName = ldapHostName; + Assert.AreEqual( ldapHostName, sut.LDAPHostName, "LDAPHostName" ); + + const string objectClassName = "DOES NOT MATTER"; + sut.ObjectClass = objectClassName; + Assert.AreEqual( objectClassName, sut.ObjectClass, "ObjectClass" ); + + //test with the negate of the default value + var searchChildDomains = !sut.SearchChildDomains; + sut.SearchChildDomains = searchChildDomains; + Assert.AreEqual( searchChildDomains, sut.SearchChildDomains, "SearchChildDomains" ); + + var searchContext = TestHelpers.GetProperties( + typeof( ActiveDirectoryConnector ) ).GetProperty( ConfigHelper.CONFIG_PROPERTY_SEARCH_CONTEXT ); + sut.SearchContext = searchContext; + Assert.AreEqual( searchContext, sut.SearchContext, "SearchContext" ); + + var syncDomainController = TestHelpers.GetProperties( + typeof( ActiveDirectoryConnector ) ).GetProperty( ConfigHelper.CONFIG_PROPERTY_SYNC_DOMAIN_CONTROLLER ); + sut.SyncDomainController = syncDomainController; + Assert.AreEqual( syncDomainController, sut.SyncDomainController, "SyncDomainController" ); + + var syncGlobalCatalogServer = TestHelpers.GetProperties( + typeof( ActiveDirectoryConnector ) ).GetProperty( ConfigHelper.CONFIG_PROPERTY_GC_DOMAIN_CONTROLLER ); + sut.SyncGlobalCatalogServer = syncGlobalCatalogServer; + Assert.AreEqual( syncGlobalCatalogServer, sut.SyncGlobalCatalogServer, "SyncGlobalCatalogServer" ); + } + + [Test] + public void TestValidate() + { + var sut = (ActiveDirectoryConfiguration)ConfigHelper.GetConfiguration(); + //test if the default configuration is valid, hence the following tests will fail only if the + //changed property is incorrect + sut.Validate(); + + var domainName = sut.DomainName; + try + { + sut.DomainName = string.Empty; + sut.Validate(); + Assert.Fail( "Exception was not thrown for empty DomainName" ); + } + catch(ConfigurationException) + { + sut.DomainName = domainName; + } + + var directoryAdminName = sut.DirectoryAdminName; + try + { + sut.DirectoryAdminName = string.Empty; + sut.Validate(); + Assert.Fail( "Exception was not thrown for empty DirectoryAdminName" ); + } + catch (ConfigurationException) + { + sut.DirectoryAdminName = directoryAdminName; + } + + var directoryAdminPassword = sut.DirectoryAdminPassword; + try + { + sut.DirectoryAdminPassword = string.Empty; + sut.Validate(); + Assert.Fail( "Exception was not thrown for empty DirectoryAdminPassword" ); + } + catch (ConfigurationException) + { + sut.DirectoryAdminPassword = directoryAdminPassword; + } + + var objectClass = sut.ObjectClass; + try + { + sut.ObjectClass = string.Empty; + sut.Validate(); + Assert.Fail( "Exception was not thrown for empty ObjectClass" ); + } + catch (ConfigurationException) + { + sut.ObjectClass = objectClass; + } + + + var container = sut.Container; + try + { + sut.Container = string.Empty; + sut.Validate(); + Assert.Fail( "Exception was not thrown for empty Container" ); + + sut.Container = "CN=ClaytonFarlow.DC=NotMyCompany.DC=com"; + sut.Validate(); + Assert.Fail( "Exception was not thrown for Container containing periods" ); + } + catch (ConfigurationException) + { + sut.Container = container; + } + } + } +} diff --git a/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTest.cs b/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTest.cs index eaa15c3..e91769d 100644 --- a/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTest.cs +++ b/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTest.cs @@ -43,65 +43,55 @@ namespace Org.IdentityConnectors.ActiveDirectory public class ActiveDirectoryConnectorTest { Random _rand = new Random(); - public static readonly string CONFIG_PROPERTY_USER = "config_user"; - public static readonly string CONFIG_PROPERTY_PASSWORD = "config_password"; - public static readonly string CONFIG_PROPERTY_HOST = "config_host"; - public static readonly string CONFIG_PROPERTY_PORT = "config_port"; - public static readonly string CONFIG_PROPERTY_CONTAINER = "config_container"; - public static readonly string CONFIG_PROPERTY_SCRIPT_USER_LOCAL = "config_script_user_local"; - public static readonly string CONFIG_PROPERTY_SCRIPT_PASSWORD_LOCAL = "config_script_password_local"; - public static readonly string CONFIG_PROPERTY_SCRIPT_USER_DOMAIN = "config_script_user_domain"; - public static readonly string CONFIG_PROPERTY_SCRIPT_PASSWORD_DOMAIN = "config_script_password_domain"; - public static readonly string CONFIG_PROPERTY_LDAPHOSTNAME = "config_ldap_hostname"; - public static readonly string CONFIG_PROPERTY_SEARCH_CONTEXT = "config_search_context"; - public static readonly string config_PROPERTY_SYNC_CONTAINER_ROOT = "config_sync_container_root"; - public static readonly string config_PROPERTY_SYNC_CONTAINER_CHILD = "config_sync_container_child"; - public static readonly string CONFIG_PROPERTY_DOMAIN_NAME = "config_domain_name"; - public static readonly string CONFIG_PROPERTY_SYNC_DOMAIN_CONTROLLER = "config_sync_domain_controller"; - public static readonly string CONFIG_PROPERTY_GC_DOMAIN_CONTROLLER = "config_sync_gc_domain_controller"; - public static readonly string TEST_PARAM_SHARED_HOME_FOLDER = "test_param_shared_home_folder"; + // having troubles with duplicate random numbers public static List randomList = new List(); - [Test] - public void TestConfiguration() { - ActiveDirectoryConfiguration config = new ActiveDirectoryConfiguration(); - config.ConnectorMessages = TestHelpers.CreateDummyMessages(); - String directoryAdminName = GetProperty(CONFIG_PROPERTY_USER); - config.DirectoryAdminName = directoryAdminName; - Assert.AreEqual(directoryAdminName, config.DirectoryAdminName); - } - [Test] public void TestTest() { ActiveDirectoryConnector connectorGood = new ActiveDirectoryConnector(); - ActiveDirectoryConfiguration config = (ActiveDirectoryConfiguration)GetConfiguration(); + ActiveDirectoryConfiguration config = (ActiveDirectoryConfiguration)ConfigHelper.GetConfiguration(); connectorGood.Init(config); connectorGood.Test(); - bool threwException = false; + var objectClass = config.ObjectClass; try { config.ObjectClass = "BadObjectClass"; ActiveDirectoryConnector connectorBad = new ActiveDirectoryConnector(); connectorBad.Init(config); connectorBad.Test(); + + Assert.Fail( "Bad configuration should have caused an exception" ); } catch (ConnectorException e) { - threwException = true; + config.ObjectClass = objectClass; } - Assert.IsTrue(threwException, "Bad configuration should have caused an exception"); + var container = config.Container; + try + { + config.Container += ",DC=BadDC"; + ActiveDirectoryConnector connectorBad = new ActiveDirectoryConnector(); + connectorBad.Init( config ); + connectorBad.Test(); + + Assert.Fail( "Configuration with bad DC in Container should have caused an exception" ); + } + catch (ConnectorException e) + { + config.Container = container; + } } [Test] public void TestSchema() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Schema schema = connector.Schema(); Boolean foundOptionalAttributes = false; Boolean foundOperationalAttributes = false; @@ -152,7 +142,7 @@ public void TestBasics_Account() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); // create user ICollection createAttributes = GetNormalAttributes_Account(); @@ -164,7 +154,7 @@ public void TestBasics_Account() new List(); Name oldName = ConnectorAttributeUtil.GetNameFromAttributes(createAttributes); String newName = ActiveDirectoryUtils.GetRelativeName(oldName); - newName = newName.Trim() + "_new, " + GetProperty(CONFIG_PROPERTY_CONTAINER); + newName = newName.Trim() + "_new, " + GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ); updateReplaceAttrs.Add(ConnectorAttributeBuilder.Build( Name.NAME, newName)); updateReplaceAttrs.Add(ConnectorAttributeBuilder.Build( @@ -192,7 +182,7 @@ public void TestBasics_Group() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid uidToDelete = null; try @@ -221,7 +211,7 @@ public void TestBasics_Group() new List(); Name oldName = ConnectorAttributeUtil.GetNameFromAttributes(createAttributes); String newName = ActiveDirectoryUtils.GetRelativeName(oldName); - newName = newName.Trim() + "_new, " + GetProperty(CONFIG_PROPERTY_CONTAINER); + newName = newName.Trim() + "_new, " + GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ); updateReplaceAttrs.Add(createUid); updateReplaceAttrs.Add(ConnectorAttributeBuilder.Build( @@ -256,7 +246,7 @@ public void TestCreate_Account() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid createUid = null; try { @@ -279,7 +269,7 @@ public void TestCreate_Group() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid createUid = null; try { @@ -302,7 +292,7 @@ public void TestCreate_OrganizationalUnit() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid createUid = null; try { @@ -327,7 +317,7 @@ public void TestCreateWithHomeDirectory_Account() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - ActiveDirectoryConfiguration config = (ActiveDirectoryConfiguration)GetConfiguration(); + ActiveDirectoryConfiguration config = (ActiveDirectoryConfiguration)ConfigHelper.GetConfiguration(); config.CreateHomeDirectory = true; connector.Init(config); Uid userUid = null; @@ -337,7 +327,7 @@ public void TestCreateWithHomeDirectory_Account() ICollection createAttributes = GetNormalAttributes_Account(); // read the homedir path, and append the samaccountname - StringBuilder homeDirPathBuilder = new StringBuilder(GetProperty(TEST_PARAM_SHARED_HOME_FOLDER)); + StringBuilder homeDirPathBuilder = new StringBuilder( GetProperty( ConfigHelper.TEST_PARAM_SHARED_HOME_FOLDER ) ); if (!homeDirPathBuilder.ToString().EndsWith("\\")) { homeDirPathBuilder.Append('\\'); @@ -419,7 +409,7 @@ public void TestCreateWithHomeDirectoryNoCreateConfig_Account() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - ActiveDirectoryConfiguration config = (ActiveDirectoryConfiguration)GetConfiguration(); + ActiveDirectoryConfiguration config = (ActiveDirectoryConfiguration)ConfigHelper.GetConfiguration(); config.CreateHomeDirectory = false; connector.Init(config); Uid userUid = null; @@ -429,7 +419,7 @@ public void TestCreateWithHomeDirectoryNoCreateConfig_Account() ICollection createAttributes = GetNormalAttributes_Account(); // read the homedir path, and append the samaccountname - StringBuilder homeDirPathBuilder = new StringBuilder(GetProperty(TEST_PARAM_SHARED_HOME_FOLDER)); + StringBuilder homeDirPathBuilder = new StringBuilder( GetProperty( ConfigHelper.TEST_PARAM_SHARED_HOME_FOLDER ) ); if (!homeDirPathBuilder.ToString().EndsWith("\\")) { homeDirPathBuilder.Append('\\'); @@ -468,7 +458,7 @@ public void TestCreateWithHomeDirectoryNoCreateConfig_Account() public void TestSearchNoFilter_Account() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - Configuration config = GetConfiguration(); + Configuration config = ConfigHelper.GetConfiguration(); config.ConnectorMessages = TestHelpers.CreateDummyMessages(); connector.Init(config); @@ -527,7 +517,7 @@ public void TestSearchNoFilter_Account() public void TestSearchNoFilter_Group() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); ICollection createdUids = new HashSet(); try @@ -584,7 +574,7 @@ public void TestSearchNoFilter_Group() public void TestSearchByName_account() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid createUid = null; @@ -655,7 +645,7 @@ public void TestSearchByName_account() public void TestSearchByName_group() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid createUid = null; @@ -726,7 +716,7 @@ public void TestSearchByName_group() public void TestSearchByCNWithWildcard_account() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid uid1 = null; Uid uid2 = null; @@ -774,7 +764,7 @@ public void TestSearchByCNWithWildcard_account() public void TestSearchByRegularAttribute_account() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid createUid = null; @@ -828,7 +818,7 @@ public void TestSearchByRegularAttribute_account() public void TestSearchByRegularAttributeWithWildcard_account() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); ICollection uids = new HashSet(); @@ -893,7 +883,7 @@ public void TestCreateWithAllAttributes_Account() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid createUid = null; try @@ -920,7 +910,7 @@ public void Test_OpAtt_Enabled_Account() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid createUid = null; try @@ -954,18 +944,18 @@ public void TestScriptOnResource() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); try { RunScript(connector, "", "", ""); - RunScript(connector, GetProperty(CONFIG_PROPERTY_SCRIPT_USER_LOCAL), - GetProperty(CONFIG_PROPERTY_SCRIPT_PASSWORD_LOCAL), ""); - RunScript(connector, GetProperty(CONFIG_PROPERTY_SCRIPT_USER_DOMAIN), - GetProperty(CONFIG_PROPERTY_SCRIPT_PASSWORD_DOMAIN), ""); + RunScript( connector, GetProperty( ConfigHelper.CONFIG_PROPERTY_SCRIPT_USER_LOCAL ), + GetProperty( ConfigHelper.CONFIG_PROPERTY_SCRIPT_PASSWORD_LOCAL ), "" ); + RunScript( connector, GetProperty( ConfigHelper.CONFIG_PROPERTY_SCRIPT_USER_DOMAIN ), + GetProperty( ConfigHelper.CONFIG_PROPERTY_SCRIPT_PASSWORD_DOMAIN ), "" ); // now try one with the prefix set - ActiveDirectoryConfiguration prefixConfig = (ActiveDirectoryConfiguration)GetConfiguration(); + ActiveDirectoryConfiguration prefixConfig = (ActiveDirectoryConfiguration)ConfigHelper.GetConfiguration(); string prefix = "UnitTest_"; connector.Dispose(); connector.Init(prefixConfig); @@ -976,7 +966,7 @@ public void TestScriptOnResource() bool scriptFailed = false; try { - RunScript(connector, GetProperty(CONFIG_PROPERTY_USER), "bogus", ""); + RunScript( connector, GetProperty( ConfigHelper.CONFIG_PROPERTY_USER ), "bogus", "" ); } catch (Exception e) { @@ -994,7 +984,7 @@ public void TestAddGroup_Account() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid groupUid = null; Uid userUid = null; try @@ -1033,7 +1023,7 @@ public void TestAddGroup_Account() public void TestRemoveAttributeValue() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid createUid = null; @@ -1043,7 +1033,7 @@ public void TestRemoveAttributeValue() ICollection attributes = new HashSet(); attributes.Add(ConnectorAttributeBuilder.Build( - "ad_container", GetProperty(CONFIG_PROPERTY_CONTAINER))); + "ad_container", GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ) ) ); attributes.Add(ConnectorAttributeBuilder.Build( "userPassword", "secret")); attributes.Add(ConnectorAttributeBuilder.Build( @@ -1056,7 +1046,7 @@ public void TestRemoveAttributeValue() "displayName", "nunit test user " + randomNumber)); attributes.Add(ConnectorAttributeBuilder.Build( Name.NAME, "cn=nunit" + randomNumber + "," + - GetProperty(CONFIG_PROPERTY_CONTAINER))); + GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ) ) ); attributes.Add(ConnectorAttributeBuilder.Build( "mail", "nunitUser" + randomNumber + "@some.com")); attributes.Add(ConnectorAttributeBuilder.Build( @@ -1096,7 +1086,7 @@ public void TestRemoveAttributeValue() public void TestContainerChange_account() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid createOuUid = null; Uid createUserUid = null; @@ -1162,7 +1152,7 @@ public void TestContainerChange_account() public void TestContainerChange_group() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid createOuUid = null; Uid createGroupUid = null; @@ -1237,7 +1227,7 @@ public void TestEnableDate() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid createUid = null; try @@ -1272,7 +1262,7 @@ public void TestDisableDate() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid createUid = null; try @@ -1310,8 +1300,8 @@ public void TestDisableDate() public void TestSyncGC() { // test with searchChildDomain (uses GC) - TestSync(true, GetProperty(config_PROPERTY_SYNC_CONTAINER_ROOT, null)); - TestSync(true, GetProperty(config_PROPERTY_SYNC_CONTAINER_CHILD, null)); + TestSync( true, GetProperty( ConfigHelper.config_PROPERTY_SYNC_CONTAINER_ROOT, null ) ); + TestSync( true, GetProperty( ConfigHelper.config_PROPERTY_SYNC_CONTAINER_CHILD, null ) ); } // test sync @@ -1319,8 +1309,8 @@ public void TestSyncGC() public void TestSyncDC() { // test withouth searchChildDomains (uses DC) - TestSync(false, GetProperty(config_PROPERTY_SYNC_CONTAINER_ROOT, null)); - TestSync(false, GetProperty(config_PROPERTY_SYNC_CONTAINER_CHILD, null)); + TestSync( false, GetProperty( ConfigHelper.config_PROPERTY_SYNC_CONTAINER_ROOT, null ) ); + TestSync( false, GetProperty( ConfigHelper.config_PROPERTY_SYNC_CONTAINER_CHILD, null ) ); } [Test] @@ -1328,7 +1318,7 @@ public void TestUserPasswordChange() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid createUid = null; try @@ -1416,7 +1406,7 @@ public void TestAuthenticateUser() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid createUid = null; try @@ -1534,7 +1524,7 @@ public void TestShortnameAndDescription() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid uidAccount = null; Uid uidGroup = null; Uid uidOu = null; @@ -1664,7 +1654,7 @@ public void TestPasswordExpiration() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid createUid = null; try @@ -1746,7 +1736,7 @@ public void TestAccountLocked() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid createUid = null; try @@ -1859,8 +1849,8 @@ public void TestSync(bool searchChildDomains, String container) { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - ActiveDirectoryConfiguration configuration = - (ActiveDirectoryConfiguration)GetConfiguration(); + ActiveDirectoryConfiguration configuration = + (ActiveDirectoryConfiguration)ConfigHelper.GetConfiguration(); configuration.SearchContext = container; configuration.SearchChildDomains = searchChildDomains; connector.Init(configuration); @@ -1959,8 +1949,8 @@ public void TestGetLastSyncToken() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - ActiveDirectoryConfiguration configuration = - (ActiveDirectoryConfiguration)GetConfiguration(); + ActiveDirectoryConfiguration configuration = + (ActiveDirectoryConfiguration)ConfigHelper.GetConfiguration(); configuration.SearchChildDomains = false; connector.Init(configuration); SyncToken noGCToken = connector.GetLatestSyncToken(ObjectClass.ACCOUNT); @@ -2280,7 +2270,7 @@ public void DeleteAndVerifyObject(ActiveDirectoryConnector connector, public void TestOuSearch() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - ActiveDirectoryConfiguration config = (ActiveDirectoryConfiguration)GetConfiguration(); + ActiveDirectoryConfiguration config = (ActiveDirectoryConfiguration)ConfigHelper.GetConfiguration(); connector.Init(config); ObjectClass OUObjectClass = ActiveDirectoryConnector.ouObjectClass; @@ -2294,7 +2284,7 @@ public void TestUnmatchedCaseGUIDSearch() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Uid userUid = null; try { @@ -2363,22 +2353,6 @@ public void VerifyObject(ActiveDirectoryConnector connector, Uid uid, VerifyObject(attributes, GetConnectorObjectFromUid(connector, oclass, uid)); } - - public Configuration GetConfiguration() - { - ActiveDirectoryConfiguration config = new ActiveDirectoryConfiguration(); - config.DomainName = GetProperty(CONFIG_PROPERTY_DOMAIN_NAME); - config.LDAPHostName = GetProperty(CONFIG_PROPERTY_LDAPHOSTNAME); - config.DirectoryAdminName = GetProperty(CONFIG_PROPERTY_USER); - config.DirectoryAdminPassword = GetProperty(CONFIG_PROPERTY_PASSWORD); - config.Container = GetProperty(CONFIG_PROPERTY_CONTAINER); - config.SearchContext = GetProperty(CONFIG_PROPERTY_SEARCH_CONTEXT); - config.SyncDomainController = GetProperty(CONFIG_PROPERTY_SYNC_DOMAIN_CONTROLLER); - config.SyncGlobalCatalogServer = GetProperty(CONFIG_PROPERTY_GC_DOMAIN_CONTROLLER); - config.ConnectorMessages = TestHelpers.CreateDummyMessages(); - return config; - } - /** * NOTES: * - cn and __NAME__ should be the same. Test if they are not @@ -2396,7 +2370,7 @@ public ICollection GetNormalAttributes_Account() // the container ... is a fabricated attribute attributes.Add(ConnectorAttributeBuilder.Build( - "ad_container", GetProperty(CONFIG_PROPERTY_CONTAINER))); + "ad_container", GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ) ) ); attributes.Add(ConnectorAttributeBuilder.Build( "userPassword", "secret")); attributes.Add(ConnectorAttributeBuilder.Build( @@ -2409,7 +2383,7 @@ public ICollection GetNormalAttributes_Account() "displayName", "nunit test user " + randomNumber)); attributes.Add(ConnectorAttributeBuilder.Build( Name.NAME, "cn=nunit" + randomNumber + "," + - GetProperty(CONFIG_PROPERTY_CONTAINER))); + GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ) ) ); attributes.Add(ConnectorAttributeBuilder.Build( "mail", "nunitUser" + randomNumber + "@some.com")); attributes.Add(ConnectorAttributeBuilder.Build( @@ -2424,7 +2398,7 @@ public ICollection GetAllAttributes_Account() // the container ... is a fabricated attribute attributes.Add(ConnectorAttributeBuilder.Build( - "ad_container", GetProperty(CONFIG_PROPERTY_CONTAINER))); + "ad_container", GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ) ) ); GuardedString password = new GuardedString(); foreach (char c in "secret") { @@ -2581,7 +2555,7 @@ public ICollection GetAllAttributes_Account() // now set name operational attribute attributes.Add(ConnectorAttributeBuilder.Build( Name.NAME, "cn=nunit" + randomNumber + "," + - GetProperty(CONFIG_PROPERTY_CONTAINER))); + GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ) ) ); /* @@ -2606,7 +2580,7 @@ public ICollection GetNormalAttributes_Group() "description", "Original Description" + randomNumber)); attributes.Add(ConnectorAttributeBuilder.Build( Name.NAME, "cn=nunitGroup" + randomNumber + "," + - GetProperty(CONFIG_PROPERTY_CONTAINER))); + GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ) ) ); attributes.Add(ConnectorAttributeBuilder.Build( "groupType", 4)); return attributes; @@ -2619,7 +2593,7 @@ public ICollection GetNormalAttributes_OrganizationalUnit() attributes.Add(ConnectorAttributeBuilder.Build( Name.NAME, "ou=nunitOU" + randomNumber + "," + - GetProperty(CONFIG_PROPERTY_CONTAINER))); + GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ) ) ); return attributes; } @@ -2775,7 +2749,7 @@ public ICollection GetDefaultAttributesToGet(ObjectClass oclass) ICollection attributesToGet = new HashSet(); ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + connector.Init( ConfigHelper.GetConfiguration() ); Schema schema = connector.Schema(); ObjectClassInfo ocInfo = schema.FindObjectClassInfo(oclass.GetObjectClassValue()); Assert.IsNotNull(ocInfo); diff --git a/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTests.csproj b/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTests.csproj index ba08f85..559a922 100644 --- a/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTests.csproj +++ b/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTests.csproj @@ -1,4 +1,4 @@ - Create Home Directory @@ -301,5 +300,10 @@ An invalid search context was supplied: {0} - + + There are no registered PowerShell snap-ins. + + + There is no supported Exchange PowerShell snap-in registered. + \ No newline at end of file diff --git a/ExchangeConnector/PSExchangeConnector.cs b/ExchangeConnector/PSExchangeConnector.cs index 71e46a4..fa01ce8 100644 --- a/ExchangeConnector/PSExchangeConnector.cs +++ b/ExchangeConnector/PSExchangeConnector.cs @@ -231,7 +231,7 @@ public override void Init(Configuration configuration) this.configuration = (ExchangeConfiguration)configuration; // create runspace instance, will be alive as long as the connector instance is alive - this.runspace = new RunSpaceInstance(RunSpaceInstance.SnapIn.Exchange); + this.runspace = new RunSpaceInstance(RunSpaceInstance.SnapIn.Exchange, configuration.ConnectorMessages); // read the object class info definitions this.mapOcInfo = ExchangeUtility.GetOCInfo(); diff --git a/ExchangeConnector/RunSpaceInstance.cs b/ExchangeConnector/RunSpaceInstance.cs index c64b0c7..a9cfb9d 100644 --- a/ExchangeConnector/RunSpaceInstance.cs +++ b/ExchangeConnector/RunSpaceInstance.cs @@ -33,8 +33,11 @@ namespace Org.IdentityConnectors.Exchange using System.Management.Automation; using System.Management.Automation.Runspaces; using System.Text; + using System.Linq; using Org.IdentityConnectors.Framework.Common.Exceptions; + using Org.IdentityConnectors.Framework.Common.Objects; + using Org.IdentityConnectors.Common; /// /// @@ -62,9 +65,14 @@ internal sealed class RunSpaceInstance : IDisposable private static readonly string ClassName = typeof(RunSpaceInstance).ToString(); /// - /// The exchange snap in name which needs to be loaded + /// The Exchange 2007 snap in name which needs to be loaded /// - private const string ExchangeSnapIn = "Microsoft.Exchange.Management.PowerShell.Admin"; + private const string Exchange2007SnapIn = "Microsoft.Exchange.Management.PowerShell.Admin"; + + /// + /// The Exchange 2010 snap in name which needs to be loaded + /// + private const string Exchange2010SnapIn = "Microsoft.Exchange.Management.PowerShell.E2010"; /// /// Instance variable keeping the @@ -80,13 +88,22 @@ internal sealed class RunSpaceInstance : IDisposable /// instance, managed resource /// private RunspaceInvoke runSpaceInvoke; + + /// + /// The catalog of localized messages. + /// + private ConnectorMessages _messageCatalog; /// /// Initializes a new instance of the class. /// /// Type of snapin to be loaded - public RunSpaceInstance(SnapIn snapin) + /// The message catalog used for conveying localized messages. + /// Thrown when is null. + public RunSpaceInstance(SnapIn snapin, ConnectorMessages messageCatalog) { + _messageCatalog = Assertions.NullChecked(messageCatalog, "messageCatalog"); + // initialize this this.InitRunSpace(snapin); } @@ -106,6 +123,15 @@ internal enum SnapIn /// Exchange } + + /// + /// Defines the various supported Exchange versions. + /// + private enum ExchangeVersion + { + E2007, + E2010 + } /// /// Test the state of this , throws if in incorrect state @@ -305,6 +331,7 @@ private void Dispose(bool disposing) } } } + _messageCatalog = null; } /// @@ -323,11 +350,24 @@ private void InitRunSpace(SnapIn snapin) switch (snapin) { case SnapIn.Exchange: - // used for force load of the exchange dll's - AppDomain.CurrentDomain.AssemblyResolve += - new ResolveEventHandler(ExchangeUtility.AssemblyResolver); - - this.runSpaceConfig.AddPSSnapIn(ExchangeSnapIn, out snapOutput); + var serverVersion = GetExchangeServerVersion(); + switch (serverVersion) + { + case ExchangeVersion.E2007: + // used for force load of the exchange dll's + AppDomain.CurrentDomain.AssemblyResolve += + new ResolveEventHandler(ExchangeUtility.AssemblyResolver2007); + + this.runSpaceConfig.AddPSSnapIn(Exchange2007SnapIn, out snapOutput); + break; + case ExchangeVersion.E2010: + // used for force load of the exchange dll's + AppDomain.CurrentDomain.AssemblyResolve += + new ResolveEventHandler(ExchangeUtility.AssemblyResolver2010); + + this.runSpaceConfig.AddPSSnapIn(Exchange2010SnapIn, out snapOutput); + break; + } break; } @@ -343,6 +383,81 @@ private void InitRunSpace(SnapIn snapin) this.runSpaceInvoke = new RunspaceInvoke(this.runSpace); Debug.WriteLine(MethodName + ":exit", ClassName); + } + + /// + /// Determines the version of the Exchange server. + /// + /// As the remote management functionality is not utilized, the Exchange powershell snap-in must be registered + /// on the local computer. Different snap-in is used to manage Exchange 2007 and 2010, hence the server version is determined by the + /// registered snap-in. + /// + /// The version of the Exchange server to manage. + /// Thrown when the version cannot be determined. + private ExchangeVersion GetExchangeServerVersion() + { + const string MethodName = "GetServerVersion"; + Debug.WriteLine(MethodName + ":entry", ClassName); + + const string ExchangeSnapinNamePrefix = "Microsoft.Exchange.Management.PowerShell."; + + ExchangeVersion? version = null; + using (var runspace = RunspaceFactory.CreateRunspace()) + { + runspace.Open(); + + using (var pipeline = runspace.CreatePipeline()) + { + var getSnapinsCommand = new Command("Get-PSSnapin"); + getSnapinsCommand.Parameters.Add("Registered"); + + pipeline.Commands.Add(getSnapinsCommand); + + var snapinList = pipeline.Invoke(); + + PipelineReader reader = pipeline.Error; + CheckErrors((IList)reader.ReadToEnd()); + + runspace.Close(); + + if ((snapinList == null) || (snapinList.Count == 0)) + { + Debug.WriteLine("No snap-in returned"); + throw new ConnectorException(_messageCatalog.Format("ex_NoPowerShellSnapins", "There are no registered PowerShell snap-ins.")); + } + + foreach (var snapin in snapinList) + { + if ((snapin.Properties["Name"] != null) && + (snapin.Properties["Name"].Value != null) && + (snapin.Properties["Name"].Value.ToString().StartsWith(ExchangeSnapinNamePrefix, + StringComparison.InvariantCultureIgnoreCase))) + { + var snapinName = snapin.Properties["Name"].Value.ToString(); + switch (snapinName.Substring(ExchangeSnapinNamePrefix.Length)) + { + case "Admin": + //Microsoft.Exchange.Management.PowerShell.Admin snap-in is used to manage Exchange 2007 + version = ExchangeVersion.E2007; + break; + case "E2010": + //Microsoft.Exchange.Management.PowerShell.E2010 snap-in is used to manage Exchange 2010 + version = ExchangeVersion.E2010; + break; + } + } + } + } + } + + if (!version.HasValue) + { + throw new ConnectorException(_messageCatalog.Format("ex_NoSupportedExchangeSnapin", + "There is no supported Exchange PowerShell snap-in registered.")); + } + + Debug.WriteLine(MethodName + ":exit", ClassName); + return version.Value; } } } From 5f46781c1beecec13e99d02ebeb87359e185124a Mon Sep 17 00:00:00 2001 From: lajos_nagy Date: Wed, 31 Mar 2010 21:26:39 +0000 Subject: [PATCH 08/33] Issue #633: Method not found error while initializing Exchange connector --- ExchangeConnector/RunSpaceInstance.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ExchangeConnector/RunSpaceInstance.cs b/ExchangeConnector/RunSpaceInstance.cs index a9cfb9d..ec0b110 100644 --- a/ExchangeConnector/RunSpaceInstance.cs +++ b/ExchangeConnector/RunSpaceInstance.cs @@ -102,7 +102,8 @@ internal sealed class RunSpaceInstance : IDisposable /// Thrown when is null. public RunSpaceInstance(SnapIn snapin, ConnectorMessages messageCatalog) { - _messageCatalog = Assertions.NullChecked(messageCatalog, "messageCatalog"); + Assertions.NullCheck( messageCatalog, "messageCatalog" ); + _messageCatalog = messageCatalog; // initialize this this.InitRunSpace(snapin); From 2bf85657a3a1e85279131422f52e675cec6ea75a Mon Sep 17 00:00:00 2001 From: Laszlo Hordos Date: Tue, 31 May 2011 13:14:37 +0000 Subject: [PATCH 09/33] Replace the precoded framework directory dll path with OPENICF_HOME environment variables. --- .../ActiveDirectoryConnector.csproj | 8 ++++---- .../ActiveDirectoryConnectorTests.csproj | 12 ++++++------ DotNetCommonBuild.Targets | 2 +- ExchangeConnector/ExchangeConnector.csproj | 6 +++--- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ActiveDirectoryConnector/ActiveDirectoryConnector.csproj b/ActiveDirectoryConnector/ActiveDirectoryConnector.csproj index 71c1ce4..e069fd6 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryConnector.csproj +++ b/ActiveDirectoryConnector/ActiveDirectoryConnector.csproj @@ -31,7 +31,7 @@ ActiveDirectoryConnector v3.5 true - ..\..\framework\dotnet + $(OPENICF_HOME) prompt @@ -59,12 +59,12 @@ False - $(ConnectorFrameworkDir)\Dist\Common.dll + $(ConnectorFrameworkDir)\Common.dll False False - $(ConnectorFrameworkDir)\Dist\Framework.dll + $(ConnectorFrameworkDir)\Framework.dll False @@ -155,7 +155,7 @@ diff --git a/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTests.csproj b/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTests.csproj index 559a922..e9997ef 100644 --- a/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTests.csproj +++ b/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTests.csproj @@ -35,7 +35,7 @@ 512 - ..\..\framework\dotnet + $(OPENICF_HOME) true @@ -60,23 +60,23 @@ False - $(ConnectorFrameworkDir)\Dist\Common.dll + $(ConnectorFrameworkDir)\Common.dll False - $(ConnectorFrameworkDir)\Dist\Framework.dll + $(ConnectorFrameworkDir)\Framework.dll False - $(ConnectorFrameworkDir)\Dist\FrameworkInternal.dll + $(ConnectorFrameworkDir)\FrameworkInternal.dll False - $(ConnectorFrameworkDir)\Dist\Shell.ScriptExecutorFactory.dll + $(ConnectorFrameworkDir)\Shell.ScriptExecutorFactory.dll False - $(ConnectorFrameworkDir)\Dist\TestCommon.dll + $(ConnectorFrameworkDir)\TestCommon.dll diff --git a/DotNetCommonBuild.Targets b/DotNetCommonBuild.Targets index ff4eac8..88712b0 100644 --- a/DotNetCommonBuild.Targets +++ b/DotNetCommonBuild.Targets @@ -25,7 +25,7 @@ $(MSBuildProjectDirectory)\version.template $(MSBuildProjectDirectory)\version.txt - Sun Microsystems, Inc. + ForgeRock AS Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved. $(MSBuildProjectDirectory)\..\Build diff --git a/ExchangeConnector/ExchangeConnector.csproj b/ExchangeConnector/ExchangeConnector.csproj index b364f3a..a3fcbf5 100644 --- a/ExchangeConnector/ExchangeConnector.csproj +++ b/ExchangeConnector/ExchangeConnector.csproj @@ -35,7 +35,7 @@ v3.5 512 true - ..\..\framework\dotnet + $(OPENICF_HOME) false ExchangeConnectorTests @@ -60,12 +60,12 @@ False - $(ConnectorFrameworkDir)\Dist\Common.dll + $(ConnectorFrameworkDir)\Common.dll False False - $(ConnectorFrameworkDir)\Dist\Framework.dll + $(ConnectorFrameworkDir)\Framework.dll False From e5311bf0b93e5a7afff153a33e48f185eb663934 Mon Sep 17 00:00:00 2001 From: Laszlo Hordos Date: Tue, 29 May 2012 08:18:09 +0000 Subject: [PATCH 10/33] OPENICF-24 CR-422 AD Connector releases the allocated memory properly --- .../ActiveDirectoryConnector.cs | 321 +++++++++++------- .../ActiveDirectoryUtils.cs | 2 + .../CustomAttributeHandlers.cs | 15 +- .../PasswordChangeHandler.cs | 6 +- .../TerminalServicesUtils.cs | 9 +- 5 files changed, 225 insertions(+), 128 deletions(-) diff --git a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs b/ActiveDirectoryConnector/ActiveDirectoryConnector.cs index e97a2ce..3f3af56 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryConnector.cs @@ -99,6 +99,8 @@ public class ActiveDirectoryConnector : CreateOp, Connector, SchemaOp, DeleteOp, ActiveDirectoryConfiguration _configuration = null; ActiveDirectoryUtils _utils = null; private static Schema _schema = null; + private DirectoryEntry _dirHandler = null; + //private DirectorySearcher searcher = null; public ActiveDirectoryConnector() { // populate default attributes and Schema @@ -112,6 +114,7 @@ public virtual Uid Create(ObjectClass oclass, { Uid uid = null; bool created = false; + DirectoryEntry containerDe = null; DirectoryEntry newDe = null; // I had lots of problems here. Here are the things @@ -142,7 +145,7 @@ public virtual Uid Create(ObjectClass oclass, ActiveDirectoryUtils.GetParentDn(nameAttribute.GetNameValue())); String ldapEntryPath = ActiveDirectoryUtils.GetLDAPPath(_configuration.LDAPHostName, nameAttribute.GetNameValue()); - + try { if (!DirectoryEntry.Exists(ldapContainerPath)) @@ -151,7 +154,7 @@ public virtual Uid Create(ObjectClass oclass, } // Get the correct container, and put the new user in it - DirectoryEntry containerDe = new DirectoryEntry(ldapContainerPath, + containerDe = new DirectoryEntry(ldapContainerPath, _configuration.DirectoryAdminName, _configuration.DirectoryAdminPassword); newDe = containerDe.Children.Add( ActiveDirectoryUtils.GetRelativeName(nameAttribute), @@ -159,7 +162,7 @@ public virtual Uid Create(ObjectClass oclass, if (oclass.Equals(ActiveDirectoryConnector.groupObjectClass)) { - ConnectorAttribute groupAttribute = + ConnectorAttribute groupAttribute = ConnectorAttributeUtil.Find(ActiveDirectoryConnector.ATT_GROUP_TYPE, attributes); if (groupAttribute != null) { @@ -174,7 +177,7 @@ public virtual Uid Create(ObjectClass oclass, newDe.CommitChanges(); created = true; // default to creating users enabled - if ((ObjectClass.ACCOUNT.Equals(oclass)) && + if ((ObjectClass.ACCOUNT.Equals(oclass)) && (ConnectorAttributeUtil.Find(OperationalAttributes.ENABLE_NAME, attributes) == null)) { attributes.Add(ConnectorAttributeBuilder.Build(OperationalAttributes.ENABLE_NAME, true)); @@ -213,7 +216,7 @@ public virtual Uid Create(ObjectClass oclass, } throw; } - catch(Exception exception) + catch (Exception exception) { Console.WriteLine("caught exception:" + exception); Trace.TraceError(exception.Message); @@ -225,6 +228,17 @@ public virtual Uid Create(ObjectClass oclass, } throw; } + finally + { + if (containerDe != null) + { + containerDe.Dispose(); + } + if (newDe != null) + { + newDe.Dispose(); + } + } if (!oclass.Equals(ObjectClass.ACCOUNT)) { @@ -250,6 +264,17 @@ public virtual void Init(Configuration configuration) configuration.Validate(); _configuration = (ActiveDirectoryConfiguration)configuration; _utils = new ActiveDirectoryUtils(_configuration); + + // since we are a poolable connector, let's establish a persistent connection to AD + bool useGC = false; + if (_configuration.SearchChildDomains) + { + useGC = true; + } + string path = GetSearchContainerPath(useGC, _configuration.LDAPHostName, _configuration.Container); + Trace.TraceInformation("Search: Getting root node for search"); + _dirHandler = new DirectoryEntry(path,_configuration.DirectoryAdminName, _configuration.DirectoryAdminPassword); + //searcher = new DirectorySearcher(_dirHandler); } #endregion @@ -258,6 +283,10 @@ public virtual void Init(Configuration configuration) public virtual void Dispose() { + if (_dirHandler != null) + { + _dirHandler.Dispose(); + } } #endregion @@ -405,7 +434,7 @@ public virtual void ExecuteQuery(ObjectClass oclass, string query, ResultsHandler handler, OperationOptions options) { try - { + { bool useGC = false; if (_configuration.SearchChildDomains) { @@ -538,146 +567,197 @@ private void ExecuteQuery(ObjectClass oclass, string query, Trace.TraceInformation("Setting search string to \'{0}\'", query); } - string path; - path = GetSearchContainerPath(useGlobalCatalog, serverName, searchRoot); - - Trace.TraceInformation("Search: Getting root node for search"); - DirectoryEntry searchRootEntry = new DirectoryEntry(path, - _configuration.DirectoryAdminName, _configuration.DirectoryAdminPassword); - DirectorySearcher searcher = new DirectorySearcher(searchRootEntry, query); - searcher.PageSize = 1000; - searcher.SearchScope = searchScope; - - if (includeDeleted) + DirectorySearcher searcher = null; + DirectoryEntry searchRootEntry = null; + try { - searcher.Tombstone = true; - } + if (searchRoot.Equals(_configuration.Container, StringComparison.OrdinalIgnoreCase)) + { + searcher = new DirectorySearcher(_dirHandler, query); + } + else + { + // options give a different root context for search, let use a new connection + string path; + path = GetSearchContainerPath(useGlobalCatalog, serverName, searchRoot); + Trace.TraceInformation("Search: Getting root node for search"); + searchRootEntry = new DirectoryEntry(path, _configuration.DirectoryAdminName, _configuration.DirectoryAdminPassword); + searcher = new DirectorySearcher(searchRootEntry, query); + } - if (sortOption != null) - { - searcher.Sort = sortOption; - } + searcher.PageSize = 1000; + searcher.SearchScope = searchScope; - Trace.TraceInformation("Search: Performing query"); - SearchResultCollection resultSet = searcher.FindAll(); - Trace.TraceInformation("Search: found {0} results", resultSet.Count); - ICollection attributesToReturn = null; - if (resultSet.Count > 0) - { - attributesToReturn = GetAttributesToReturn(oclass, options); - } + if (includeDeleted) + { + searcher.Tombstone = true; + } - Trace.TraceInformation("Building connectorObjects"); - foreach (SearchResult result in resultSet) - { - try + if (sortOption != null) { - Trace.TraceInformation("Found object {0}", result.Path); - ConnectorObjectBuilder builder = new ConnectorObjectBuilder(); - builder.ObjectClass = oclass; + searcher.Sort = sortOption; + } - bool isDeleted = false; - if (result.Properties.Contains(ATT_IS_DELETED)) + Trace.TraceInformation("Search: Performing query"); + + // trying to avoid FindAll() as much as possible + ICollection attributesToReturn = null; + + //if (query.Contains("objectGUID=")) + //{ + // // we assume exact query + // SearchResult res = searcher.FindOne(); + // if (res != null) + // { + // attributesToReturn = GetAttributesToReturn(oclass, options); + // Trace.TraceInformation("Building connectorObject"); + // buildConnectorObject(res, oclass, useGlobalCatalog, searchRoot, attributesToReturn, handler); + // } + //} + //else + //{ + SearchResultCollection resultSet = searcher.FindAll(); + Trace.TraceInformation("Search: found {0} results", resultSet.Count); + + if (resultSet.Count > 0) { - ResultPropertyValueCollection pvc = result.Properties[ATT_IS_DELETED]; - if (pvc.Count > 0) + attributesToReturn = GetAttributesToReturn(oclass, options); + Trace.TraceInformation("Building connectorObjects"); + foreach (SearchResult result in resultSet) { - isDeleted = (bool)pvc[0]; + buildConnectorObject(result, oclass, useGlobalCatalog, searchRoot, attributesToReturn, handler); } } + // Important to dispose to avoid memory leak + resultSet.Dispose(); + //} + } + catch (Exception e) + { + Trace.TraceWarning(e.Message); + } + finally + { + //searcher.Dispose(); + if (searchRootEntry != null) + { + searchRootEntry.Dispose(); + } + } + } + + + private void buildConnectorObject(SearchResult result, ObjectClass oclass, bool useGlobalCatalog, string searchRoot, ICollection attributesToReturn, ResultsHandler handler) + { + try + { + Trace.TraceInformation("Found object {0}", result.Path); + ConnectorObjectBuilder builder = new ConnectorObjectBuilder(); + builder.ObjectClass = oclass; - if (isDeleted.Equals(false)) + bool isDeleted = false; + if (result.Properties.Contains(ATT_IS_DELETED)) + { + ResultPropertyValueCollection pvc = result.Properties[ATT_IS_DELETED]; + if (pvc.Count > 0) { - // if we were using the global catalog (gc), we have to - // now retrieve the object from a domain controller (dc) - // because the gc may not have have all of the attributes, - // depending on which attributes are replicated to the gc. - SearchResult savedGcResult = null; - SearchResult savedDcResult = result; - if (useGlobalCatalog) - { - savedGcResult = result; + isDeleted = (bool)pvc[0]; + } + } - String dcSearchRootPath = ActiveDirectoryUtils.GetLDAPPath( - _configuration.LDAPHostName, searchRoot); + if (isDeleted.Equals(false)) + { + // if we were using the global catalog (gc), we have to + // now retrieve the object from a domain controller (dc) + // because the gc may not have have all of the attributes, + // depending on which attributes are replicated to the gc. + SearchResult savedGcResult = null; + SearchResult savedDcResult = result; + if (useGlobalCatalog) + { + savedGcResult = result; - DirectoryEntry dcSearchRoot = new DirectoryEntry(dcSearchRootPath, - _configuration.DirectoryAdminName, _configuration.DirectoryAdminPassword); + String dcSearchRootPath = ActiveDirectoryUtils.GetLDAPPath( + _configuration.LDAPHostName, searchRoot); - string dcSearchQuery = String.Format("(" + ATT_DISTINGUISHED_NAME + "={0})", - ActiveDirectoryUtils.GetDnFromPath(savedGcResult.Path)); - DirectorySearcher dcSearcher = - new DirectorySearcher(dcSearchRoot, dcSearchQuery); - savedDcResult = dcSearcher.FindOne(); - if (savedDcResult == null) - { - // in this case, there is no choice, but to use - // what is in the global catalog. We would have - //liked to have read from the regular ldap, but there - // is not one. This is the case for domainDNS objects - // (at least for child domains in certain or maybe all - // circumstances). - savedDcResult = savedGcResult; - } - } + DirectoryEntry dcSearchRoot = new DirectoryEntry(dcSearchRootPath, + _configuration.DirectoryAdminName, _configuration.DirectoryAdminPassword); - foreach (string attributeName in attributesToReturn) + string dcSearchQuery = String.Format("(" + ATT_DISTINGUISHED_NAME + "={0})", + ActiveDirectoryUtils.GetDnFromPath(savedGcResult.Path)); + DirectorySearcher dcSearcher = + new DirectorySearcher(dcSearchRoot, dcSearchQuery); + savedDcResult = dcSearcher.FindOne(); + if (savedDcResult == null) { - SearchResult savedResults = savedDcResult; - // if we are using the global catalog, we had to get the - // dc's version of the directory entry, but for usnchanged, - // we need the gc version of it - if (useGlobalCatalog && attributeName.Equals(ATT_USN_CHANGED, - StringComparison.CurrentCultureIgnoreCase)) - { - savedResults = savedGcResult; - } - - AddAttributeIfNotNull(builder, - _utils.GetConnectorAttributeFromADEntry( - oclass, attributeName, savedResults)); + // in this case, there is no choice, but to use + // what is in the global catalog. We would have + //liked to have read from the regular ldap, but there + // is not one. This is the case for domainDNS objects + // (at least for child domains in certain or maybe all + // circumstances). + savedDcResult = savedGcResult; } + dcSearcher.Dispose(); + dcSearchRoot.Dispose(); } - else - { - // get uid - AddAttributeIfNotNull(builder, - _utils.GetConnectorAttributeFromADEntry( - oclass, Uid.NAME, result)); - // get uid - AddAttributeIfNotNull(builder, - _utils.GetConnectorAttributeFromADEntry( - oclass, Name.NAME, result)); + foreach (string attributeName in attributesToReturn) + { + SearchResult savedResults = savedDcResult; + // if we are using the global catalog, we had to get the + // dc's version of the directory entry, but for usnchanged, + // we need the gc version of it + if (useGlobalCatalog && attributeName.Equals(ATT_USN_CHANGED, + StringComparison.CurrentCultureIgnoreCase)) + { + savedResults = savedGcResult; + } - // get usnchanged AddAttributeIfNotNull(builder, _utils.GetConnectorAttributeFromADEntry( - oclass, ATT_USN_CHANGED, result)); - - // add isDeleted - builder.AddAttribute(ATT_IS_DELETED, true); + oclass, attributeName, savedResults)); } - - String msg = String.Format("Returning ''{0}''", - (result.Path != null) ? result.Path : ""); - Trace.TraceInformation(msg); - handler(builder.Build()); - } - catch (DirectoryServicesCOMException e) - { - // there is a chance that we found the result, but - // in the mean time, it was deleted. In that case, - // log an error and continue - Trace.TraceWarning("Error in creating ConnectorObject from DirectoryEntry. It may have been deleted during search."); - Trace.TraceWarning(e.Message); } - catch (Exception e) + else { - // In that case, of any error, try to continue - Trace.TraceWarning("Error in creating ConnectorObject from DirectoryEntry."); - Trace.TraceWarning(e.Message); + // get uid + AddAttributeIfNotNull(builder, + _utils.GetConnectorAttributeFromADEntry( + oclass, Uid.NAME, result)); + + // get uid + AddAttributeIfNotNull(builder, + _utils.GetConnectorAttributeFromADEntry( + oclass, Name.NAME, result)); + + // get usnchanged + AddAttributeIfNotNull(builder, + _utils.GetConnectorAttributeFromADEntry( + oclass, ATT_USN_CHANGED, result)); + + // add isDeleted + builder.AddAttribute(ATT_IS_DELETED, true); } + + String msg = String.Format("Returning ''{0}''", + (result.Path != null) ? result.Path : ""); + Trace.TraceInformation(msg); + handler(builder.Build()); + } + catch (DirectoryServicesCOMException e) + { + // there is a chance that we found the result, but + // in the mean time, it was deleted. In that case, + // log an error and continue + Trace.TraceWarning("Error in creating ConnectorObject from DirectoryEntry. It may have been deleted during search."); + Trace.TraceWarning(e.Message); + } + catch (Exception e) + { + // In that case, of any error, try to continue + Trace.TraceWarning("Error in creating ConnectorObject from DirectoryEntry."); + Trace.TraceWarning(e.Message); } } @@ -837,6 +917,7 @@ public virtual Uid Update(UpdateType type, ObjectClass oclass, updatedUid = new Uid(ActiveDirectoryUtils.NormalizeLdapString(dnUid)); } } + updateEntry.Dispose(); return updatedUid; } @@ -879,6 +960,7 @@ public virtual void Delete(ObjectClass objClass, Uid uid, OperationOptions optio // delete this entry and all it's children de.DeleteTree(); } + de.Dispose(); } #endregion @@ -1041,6 +1123,7 @@ public virtual void Sync(ObjectClass objClass, SyncToken token, { DirectoryEntry domainDe = domain.GetDirectoryEntry(); deleteObjectsSearchRoot = ActiveDirectoryUtils.GetDnFromPath(domainDe.Path); + domainDe.Dispose(); } ExecuteQuery(objClass, deletedQuery, syncResults.SyncHandler, builder.Build(), true, new SortOption(ATT_USN_CHANGED, SortDirection.Ascending), diff --git a/ActiveDirectoryConnector/ActiveDirectoryUtils.cs b/ActiveDirectoryConnector/ActiveDirectoryUtils.cs index 70ea06e..0665266 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryUtils.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryUtils.cs @@ -472,6 +472,7 @@ internal static DirectoryEntry GetDirectoryEntryFromUid(String serverName, ActiveDirectoryUtils.GetLDAPPath(serverName, uid.GetUidValue()), adminUserName, adminPassword); string dn = (string)foundDirectoryEntry.Properties["distinguishedName"][0]; + foundDirectoryEntry.Dispose(); foundDirectoryEntry = new DirectoryEntry( ActiveDirectoryUtils.GetLDAPPath(serverName, dn), adminUserName, adminPassword); @@ -611,6 +612,7 @@ private static void HandleContainerChange(UpdateType type, DirectoryEntry newContainerDe = new DirectoryEntry(newContainerLdapPath, config.DirectoryAdminName, config.DirectoryAdminPassword); directoryEntry.MoveTo(newContainerDe); + newContainerDe.Dispose(); } } catch (Exception e) diff --git a/ActiveDirectoryConnector/CustomAttributeHandlers.cs b/ActiveDirectoryConnector/CustomAttributeHandlers.cs index 74f30f8..1671665 100644 --- a/ActiveDirectoryConnector/CustomAttributeHandlers.cs +++ b/ActiveDirectoryConnector/CustomAttributeHandlers.cs @@ -375,6 +375,7 @@ internal void UpdateDeFromCa_OpAtt_Groups(ObjectClass oclass, String distinguishedName = ActiveDirectoryUtils.GetDnFromPath(directoryEntry.Path); groupDe.Properties[ActiveDirectoryConnector.ATT_MEMBER].Remove(distinguishedName); groupDe.CommitChanges(); + groupDe.Dispose(); } foreach (Object obj in groupsToAdd) @@ -388,6 +389,7 @@ internal void UpdateDeFromCa_OpAtt_Groups(ObjectClass oclass, String distinguishedName = ActiveDirectoryUtils.GetDnFromPath(directoryEntry.Path); groupDe.Properties[ActiveDirectoryConnector.ATT_MEMBER].Add(distinguishedName); groupDe.CommitChanges(); + groupDe.Dispose(); } } else @@ -897,13 +899,15 @@ private ConnectorAttribute GetCaFromDe_Att_Container( return null; } - DirectoryEntry parentDe = searchResult.GetDirectoryEntry().Parent; + DirectoryEntry de = searchResult.GetDirectoryEntry(); + DirectoryEntry parentDe = de.Parent; String container = ""; if (parentDe != null) { container = ActiveDirectoryUtils.GetDnFromPath(parentDe.Path); } - + parentDe.Dispose(); + de.Dispose(); return ConnectorAttributeBuilder.Build( ActiveDirectoryConnector.ATT_CONTAINER, container); } @@ -947,11 +951,11 @@ private ConnectorAttribute GetCaFromDe_OpAtt_Enabled( { return null; } - + DirectoryEntry de = searchResult.GetDirectoryEntry(); bool disabled = UserAccountControl.IsSet( - searchResult.GetDirectoryEntry().Properties[UserAccountControl.UAC_ATTRIBUTE_NAME], + de.Properties[UserAccountControl.UAC_ATTRIBUTE_NAME], UserAccountControl.ACCOUNTDISABLE); - + de.Dispose(); return ConnectorAttributeBuilder.BuildEnabled(!disabled); } @@ -1070,6 +1074,7 @@ private ConnectorAttribute GetCaFromDe_PasswordNeverExpires( UserAccountControl.DONT_EXPIRE_PASSWORD); ca = ConnectorAttributeBuilder.Build(attributeName, pne); } + de.Dispose(); } return ca; } diff --git a/ActiveDirectoryConnector/PasswordChangeHandler.cs b/ActiveDirectoryConnector/PasswordChangeHandler.cs index 771b28d..1e62682 100644 --- a/ActiveDirectoryConnector/PasswordChangeHandler.cs +++ b/ActiveDirectoryConnector/PasswordChangeHandler.cs @@ -123,6 +123,7 @@ internal Uid ValidateUserCredentials(string username, string password) } WindowsIdentity windowsId = new WindowsIdentity(tokenHandle); Uid uid = GetUidFromSid(windowsId.User); + windowsId.Dispose(); return uid; } catch(Exception e) @@ -145,8 +146,9 @@ internal Uid GetUidFromSid(SecurityIdentifier accountSid) DirectoryEntry userDe = new DirectoryEntry( ActiveDirectoryUtils.GetLDAPPath(_configuration.LDAPHostName, sidString), _configuration.DirectoryAdminName, _configuration.DirectoryAdminPassword); - - return new Uid(ActiveDirectoryUtils.ConvertUIDBytesToGUIDString(userDe.Guid.ToByteArray())); + byte[] guid = userDe.Guid.ToByteArray(); + userDe.Dispose(); + return new Uid(ActiveDirectoryUtils.ConvertUIDBytesToGUIDString(guid)); } internal Uid GetUidFromSamAccountName(String sAMAccountName) diff --git a/ActiveDirectoryConnector/TerminalServicesUtils.cs b/ActiveDirectoryConnector/TerminalServicesUtils.cs index 72ca639..29aad13 100644 --- a/ActiveDirectoryConnector/TerminalServicesUtils.cs +++ b/ActiveDirectoryConnector/TerminalServicesUtils.cs @@ -100,12 +100,17 @@ private static T GetValue(SearchResult searchResult, string name, T defaultVa { T value = (T)result; return value; - } - }catch (Exception e) + } + } + catch (Exception e) { Trace.TraceWarning("Unable to retrieve property called {0}", name); Trace.TraceWarning(e.Message); } + finally + { + directoryEntry.Dispose(); + } // if the name didn't exist, return 'defaultValue' return defaultValue; From 76935d4b21d3fdb015c8341deaf7f5b7b32ddac8 Mon Sep 17 00:00:00 2001 From: Gael Allioux Date: Wed, 20 Jun 2012 15:21:46 +0000 Subject: [PATCH 11/33] Fixes the NPE issue with large groups (> 1500 members) OPENIDM-598 and OPENICF-23 --- .../ActiveDirectoryConnector.cs | 39 ++---- .../CustomAttributeHandlers.cs | 120 ++++++++++++++++++ 2 files changed, 132 insertions(+), 27 deletions(-) diff --git a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs b/ActiveDirectoryConnector/ActiveDirectoryConnector.cs index 3f3af56..27ca226 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryConnector.cs @@ -600,37 +600,22 @@ private void ExecuteQuery(ObjectClass oclass, string query, Trace.TraceInformation("Search: Performing query"); - // trying to avoid FindAll() as much as possible ICollection attributesToReturn = null; - //if (query.Contains("objectGUID=")) - //{ - // // we assume exact query - // SearchResult res = searcher.FindOne(); - // if (res != null) - // { - // attributesToReturn = GetAttributesToReturn(oclass, options); - // Trace.TraceInformation("Building connectorObject"); - // buildConnectorObject(res, oclass, useGlobalCatalog, searchRoot, attributesToReturn, handler); - // } - //} - //else - //{ - SearchResultCollection resultSet = searcher.FindAll(); - Trace.TraceInformation("Search: found {0} results", resultSet.Count); - - if (resultSet.Count > 0) + SearchResultCollection resultSet = searcher.FindAll(); + Trace.TraceInformation("Search: found {0} results", resultSet.Count); + + if (resultSet.Count > 0) + { + attributesToReturn = GetAttributesToReturn(oclass, options); + Trace.TraceInformation("Building connectorObjects"); + foreach (SearchResult result in resultSet) { - attributesToReturn = GetAttributesToReturn(oclass, options); - Trace.TraceInformation("Building connectorObjects"); - foreach (SearchResult result in resultSet) - { - buildConnectorObject(result, oclass, useGlobalCatalog, searchRoot, attributesToReturn, handler); - } + buildConnectorObject(result, oclass, useGlobalCatalog, searchRoot, attributesToReturn, handler); } - // Important to dispose to avoid memory leak - resultSet.Dispose(); - //} + } + // Important to dispose to avoid memory leak + resultSet.Dispose(); } catch (Exception e) { diff --git a/ActiveDirectoryConnector/CustomAttributeHandlers.cs b/ActiveDirectoryConnector/CustomAttributeHandlers.cs index 1671665..0b25a80 100644 --- a/ActiveDirectoryConnector/CustomAttributeHandlers.cs +++ b/ActiveDirectoryConnector/CustomAttributeHandlers.cs @@ -54,6 +54,8 @@ namespace Org.IdentityConnectors.ActiveDirectory /// internal class CustomAttributeHandlers { + // Max range retrieval to obtain the members of a group + private static readonly int GRP_MEMBERS_MAXRANGE = 1500; // names from active directory attributes to ignore during // generic translation IList IgnoreADAttributeNames_account = new List(); @@ -170,6 +172,8 @@ internal CustomAttributeHandlers(ActiveDirectoryConfiguration configuration) { GetCaFromDe_OpAtt_Accounts); GetCaFromDeDelegates.Add(PredefinedAttributes.GROUPS_NAME, GetCaFromDe_OpAtt_Groups); + GetCaFromDeDelegates.Add(ActiveDirectoryConnector.ATT_MEMBER, + GetCaFromDe_OpAtt_GroupMembers); GetCaFromDeDelegates.Add(OperationalAttributes.ENABLE_NAME, GetCaFromDe_OpAtt_Enabled); GetCaFromDeDelegates.Add(OperationalAttributes.PASSWORD_EXPIRED_NAME, @@ -840,6 +844,122 @@ private ConnectorAttribute GetCaFromDe_Att_Generic( return attributeBuilder.Build(); } + private ConnectorAttribute GetCaFromDe_OpAtt_GroupMembers( + ObjectClass oclass, string attributeName, SearchResult searchResult) + { + ConnectorAttributeBuilder attributeBuilder = new ConnectorAttributeBuilder(); + + if (attributeName == null) + { + return null; + } + + attributeBuilder.Name = attributeName; + + ResultPropertyValueCollection pvc = null; + if (searchResult.Properties.Contains(attributeName)) + { + pvc = searchResult.Properties[attributeName]; + } + + // Range issue most probably... + // see: http://msdn.microsoft.com/en-us/library/ms817827.aspx + if (pvc.Count == 0) + { + DirectoryEntry entry = null; + DirectorySearcher searcher = null; + + int first = 0; + int last = first + (GRP_MEMBERS_MAXRANGE - 1); + bool badQuery = false; + bool quit = false; + string memberRange; + + try + { + entry = searchResult.GetDirectoryEntry(); + searcher = new DirectorySearcher(entry); + searcher.Filter = "(objectClass=*)"; + do + { + if (!badQuery) + { + memberRange = String.Format("member;range={0}-{1}", first, last); + } + else + { + memberRange = String.Format("member;range={0}-*", first); + } + searcher.PropertiesToLoad.Clear(); + searcher.PropertiesToLoad.Add(memberRange); + SearchResult sresult = searcher.FindOne(); + if (sresult.Properties.Contains(memberRange)) + { + foreach (object valueObject in sresult.Properties[memberRange]) + { + if ((valueObject == null) || (FrameworkUtil.IsSupportedAttributeType(valueObject.GetType()))) + { + attributeBuilder.AddValue(valueObject); + } + } + if (badQuery) + { + quit = true; + } + } + else + { + badQuery = true; + } + if (!badQuery) + { + first = last + 1; + last = first + (GRP_MEMBERS_MAXRANGE - 1); + } + } + while (!quit); + } + catch (Exception ex) + { + } + finally + { + if (entry != null) + { + entry.Dispose(); + } + if (searcher != null) + { + searcher.Dispose(); + } + } + return attributeBuilder.Build(); + } + else if (pvc == null) + { + return null; + } + else + { + for (int i = 0; i < pvc.Count; i++) + { + Object valueObject = pvc[i]; + if ((pvc[i] == null) || + (FrameworkUtil.IsSupportedAttributeType(valueObject.GetType()))) + { + attributeBuilder.AddValue(pvc[i]); + } + else + { + Trace.TraceWarning( + "Unsupported attribute type ... calling ToString (Name: \'{0}\'({1}) Type: \'{2}\' String Value: \'{3}\'", + attributeName, i, pvc[i].GetType(), pvc[i].ToString()); + attributeBuilder.AddValue(pvc[i].ToString()); + } + } + } + return attributeBuilder.Build(); + } private ConnectorAttribute GetCaFromDe_OpAtt_Name( ObjectClass oclass, string attributeName, SearchResult searchResult) { From f46ac1e7404ca0273e14509b9e7ffbd7ff07ff31 Mon Sep 17 00:00:00 2001 From: Gael Allioux Date: Fri, 10 Aug 2012 12:44:41 +0000 Subject: [PATCH 12/33] Small refactoring of the search to avoid calling 'count' on SearchResultSet --- .../ActiveDirectoryConnector.cs | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs b/ActiveDirectoryConnector/ActiveDirectoryConnector.cs index 27ca226..bfedf97 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryConnector.cs @@ -601,21 +601,27 @@ private void ExecuteQuery(ObjectClass oclass, string query, Trace.TraceInformation("Search: Performing query"); ICollection attributesToReturn = null; - - SearchResultCollection resultSet = searcher.FindAll(); - Trace.TraceInformation("Search: found {0} results", resultSet.Count); - - if (resultSet.Count > 0) + SearchResultCollection resultSet = null; + int count = 0; + attributesToReturn = GetAttributesToReturn(oclass, options); + try { - attributesToReturn = GetAttributesToReturn(oclass, options); - Trace.TraceInformation("Building connectorObjects"); + resultSet = searcher.FindAll(); foreach (SearchResult result in resultSet) { buildConnectorObject(result, oclass, useGlobalCatalog, searchRoot, attributesToReturn, handler); + count++; + } + } + finally + { + Trace.TraceInformation("Search: found {0} results", count); + // Important to dispose to avoid memory leak + if (resultSet != null) + { + resultSet.Dispose(); } } - // Important to dispose to avoid memory leak - resultSet.Dispose(); } catch (Exception e) { From 97b392aac9653a88f981be28c057cfb60fb3cf72 Mon Sep 17 00:00:00 2001 From: Laszlo Hordos Date: Tue, 14 Aug 2012 21:04:44 +0000 Subject: [PATCH 13/33] Fix the broken default schema Add the Exchange connector to the solution file --- ActiveDirectoryConnector/ObjectClasses.xml | 9 ++++++--- DotNetConnectors.sln | 10 ++++++++-- ExchangeConnector/Data/CommandInfos.xml | 2 +- ExchangeConnector/Data/PersistenceUtility.cs | 2 +- ExchangeConnector/Data/SerializableCommandInfo.cs | 2 +- ExchangeConnector/ObjectClasses.xml | 1 + 6 files changed, 18 insertions(+), 8 deletions(-) diff --git a/ActiveDirectoryConnector/ObjectClasses.xml b/ActiveDirectoryConnector/ObjectClasses.xml index a57aa21..2da8c20 100644 --- a/ActiveDirectoryConnector/ObjectClasses.xml +++ b/ActiveDirectoryConnector/ObjectClasses.xml @@ -52,7 +52,7 @@ - + @@ -130,6 +130,7 @@ + @@ -141,11 +142,12 @@ - - + + + @@ -177,6 +179,7 @@ + diff --git a/DotNetConnectors.sln b/DotNetConnectors.sln index ceddedc..4043737 100644 --- a/DotNetConnectors.sln +++ b/DotNetConnectors.sln @@ -1,9 +1,11 @@ -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ActiveDirectoryConnector", "ActiveDirectoryConnector\ActiveDirectoryConnector.csproj", "{BDF495CA-0FCD-4E51-A871-D467CDE3B43E}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ActiveDirectoryConnectorTests", "ActiveDirectoryConnectorTests\ActiveDirectoryConnectorTests.csproj", "{DB8F7DA9-11A2-4BEB-8C14-25D8229EBE7E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExchangeConnector", "ExchangeConnector\ExchangeConnector.csproj", "{F1CB12B6-0DD7-4DAB-9B21-630449B8610D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -18,6 +20,10 @@ Global {DB8F7DA9-11A2-4BEB-8C14-25D8229EBE7E}.Debug|Any CPU.Build.0 = Debug|Any CPU {DB8F7DA9-11A2-4BEB-8C14-25D8229EBE7E}.Release|Any CPU.ActiveCfg = Release|Any CPU {DB8F7DA9-11A2-4BEB-8C14-25D8229EBE7E}.Release|Any CPU.Build.0 = Release|Any CPU + {F1CB12B6-0DD7-4DAB-9B21-630449B8610D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F1CB12B6-0DD7-4DAB-9B21-630449B8610D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F1CB12B6-0DD7-4DAB-9B21-630449B8610D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F1CB12B6-0DD7-4DAB-9B21-630449B8610D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ExchangeConnector/Data/CommandInfos.xml b/ExchangeConnector/Data/CommandInfos.xml index c0cf0cf..66c0097 100644 --- a/ExchangeConnector/Data/CommandInfos.xml +++ b/ExchangeConnector/Data/CommandInfos.xml @@ -314,4 +314,4 @@ - + diff --git a/ExchangeConnector/Data/PersistenceUtility.cs b/ExchangeConnector/Data/PersistenceUtility.cs index 7e4e468..a922d7c 100644 --- a/ExchangeConnector/Data/PersistenceUtility.cs +++ b/ExchangeConnector/Data/PersistenceUtility.cs @@ -69,4 +69,4 @@ internal static IList ReadCommandInfo() } } } -} +} diff --git a/ExchangeConnector/Data/SerializableCommandInfo.cs b/ExchangeConnector/Data/SerializableCommandInfo.cs index da08b43..5c70182 100644 --- a/ExchangeConnector/Data/SerializableCommandInfo.cs +++ b/ExchangeConnector/Data/SerializableCommandInfo.cs @@ -80,4 +80,4 @@ public void AddParameter(string parameter) this.parameters.Add(parameter); } } -} +} diff --git a/ExchangeConnector/ObjectClasses.xml b/ExchangeConnector/ObjectClasses.xml index 55f8db4..1dd71ec 100644 --- a/ExchangeConnector/ObjectClasses.xml +++ b/ExchangeConnector/ObjectClasses.xml @@ -213,6 +213,7 @@ + From 9affabc85b910e6219407fbacf8b2360eb6f4e18 Mon Sep 17 00:00:00 2001 From: Gael Allioux Date: Tue, 21 Aug 2012 07:54:28 +0000 Subject: [PATCH 14/33] fixes the OPENICF-35 Read of AD Group without members fails --- ActiveDirectoryConnector/CustomAttributeHandlers.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ActiveDirectoryConnector/CustomAttributeHandlers.cs b/ActiveDirectoryConnector/CustomAttributeHandlers.cs index 0b25a80..0f469ef 100644 --- a/ActiveDirectoryConnector/CustomAttributeHandlers.cs +++ b/ActiveDirectoryConnector/CustomAttributeHandlers.cs @@ -861,6 +861,11 @@ private ConnectorAttribute GetCaFromDe_OpAtt_GroupMembers( { pvc = searchResult.Properties[attributeName]; } + else + // Group without members + { + return null; + } // Range issue most probably... // see: http://msdn.microsoft.com/en-us/library/ms817827.aspx From cbf68551832f943046fa3d5cd0bf40f1a47d6682 Mon Sep 17 00:00:00 2001 From: Laszlo Hordos Date: Sun, 26 Aug 2012 19:50:00 +0000 Subject: [PATCH 15/33] OPENICF-37 - Fix the ActiveDirectoryConnector and ExchangeConnector packaging --- .../ActiveDirectoryConnector.csproj | 32 +--- ActiveDirectoryConnector/build.xml | 29 --- .../ActiveDirectoryConnectorTests.csproj | 24 +-- DotNetCommonBuild.Targets | 167 +++++++++--------- ExchangeConnector/ExchangeConnector.csproj | 15 +- ExchangeConnector/build.xml | 29 --- build.xml | 86 --------- 7 files changed, 103 insertions(+), 279 deletions(-) delete mode 100644 ActiveDirectoryConnector/build.xml delete mode 100644 ExchangeConnector/build.xml delete mode 100644 build.xml diff --git a/ActiveDirectoryConnector/ActiveDirectoryConnector.csproj b/ActiveDirectoryConnector/ActiveDirectoryConnector.csproj index e069fd6..3821ac3 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryConnector.csproj +++ b/ActiveDirectoryConnector/ActiveDirectoryConnector.csproj @@ -1,3 +1,4 @@ + - + {BDF495CA-0FCD-4E51-A871-D467CDE3B43E} Debug @@ -28,8 +29,7 @@ Library Org.IdentityConnectors.ActiveDirectory ActiveDirectory.Connector - ActiveDirectoryConnector - v3.5 + v4.0 true $(OPENICF_HOME) @@ -68,22 +68,13 @@ False - - 3.5 - + - - 3.5 - - - False - ..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.DirectoryServices.Protocols.dll - + + - - 3.5 - + @@ -153,13 +144,4 @@ - - - - - - \ No newline at end of file diff --git a/ActiveDirectoryConnector/build.xml b/ActiveDirectoryConnector/build.xml deleted file mode 100644 index 1e98d75..0000000 --- a/ActiveDirectoryConnector/build.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - diff --git a/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTests.csproj b/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTests.csproj index e9997ef..2b4a569 100644 --- a/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTests.csproj +++ b/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTests.csproj @@ -1,4 +1,5 @@ - - + Debug AnyCPU - 9.0.21022 2.0 {DB8F7DA9-11A2-4BEB-8C14-25D8229EBE7E} Library Properties Org.IdentityConnectors.ActiveDirectory ActiveDirectoryConnectorTests - v3.5 + v4.0 512 @@ -81,16 +81,10 @@ - - 3.5 - + - - 3.5 - - - 3.5 - + + @@ -111,7 +105,5 @@ - - if EXIST "$(SolutionDir)\ShellScriptExecutorFactory\$(OutDir)\Shell.ScriptExecutorFactory.dll". (copy "$(SolutionDir)\ShellScriptExecutorFactory\$(OutDir)\Shell.ScriptExecutorFactory.dll" "$(TargetDir)") else (echo yuck > .\delete.me.ad) - + \ No newline at end of file diff --git a/DotNetCommonBuild.Targets b/DotNetCommonBuild.Targets index 88712b0..1875685 100644 --- a/DotNetCommonBuild.Targets +++ b/DotNetCommonBuild.Targets @@ -19,91 +19,88 @@ enclosed by brackets [] replaced by your own identifying information: "Portions Copyrighted [year] [name of copyright owner]" ==================== + Portions Copyrighted 2012 ForgeRock AS --> - - - - $(MSBuildProjectDirectory)\version.template - $(MSBuildProjectDirectory)\version.txt - ForgeRock AS - Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved. - $(MSBuildProjectDirectory)\..\Build - + + + + $(MSBuildProjectDirectory)\version.template + $(MSBuildProjectDirectory)\version.txt + ForgeRock AS + Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved. + $(MSBuildProjectDirectory)\..\Build + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CommonBeforeBuild; + $(BuildDependsOn); + CommonAfterBuild + + + $(CleanDependsOn); + CommonClean + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CommonBeforeBuild; - $(BuildDependsOn); - CommonAfterBuild - - - $(CleanDependsOn); - CommonClean - - - - - - - - - - - - diff --git a/ExchangeConnector/ExchangeConnector.csproj b/ExchangeConnector/ExchangeConnector.csproj index a3fcbf5..ee53a27 100644 --- a/ExchangeConnector/ExchangeConnector.csproj +++ b/ExchangeConnector/ExchangeConnector.csproj @@ -1,4 +1,5 @@ - - + Debug AnyCPU - 9.0.30729 2.0 {F1CB12B6-0DD7-4DAB-9B21-630449B8610D} Library @@ -32,7 +32,7 @@ Org.IdentityConnectors.Exchange Exchange.Connector Exchange - v3.5 + v4.0 512 true $(OPENICF_HOME) @@ -69,12 +69,9 @@ False - - 3.5 - - + + False - ..\..\..\..\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0\System.Management.Automation.dll diff --git a/ExchangeConnector/build.xml b/ExchangeConnector/build.xml deleted file mode 100644 index fa50e66..0000000 --- a/ExchangeConnector/build.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - diff --git a/build.xml b/build.xml deleted file mode 100644 index c17d882..0000000 --- a/build.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From f0402bc186aba450efcc1f5a28189f2b3059c8ea Mon Sep 17 00:00:00 2001 From: Gael Allioux Date: Thu, 14 Mar 2013 10:12:09 +0000 Subject: [PATCH 16/33] CR1414 - fixes OPENICF-44 and OPENICF-92 --- .../ActiveDirectoryConnector.cs | 20 +------------- .../CustomAttributeHandlers.cs | 27 ++++++------------- ActiveDirectoryConnector/ObjectClasses.xml | 14 +++++++++- 3 files changed, 22 insertions(+), 39 deletions(-) diff --git a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs b/ActiveDirectoryConnector/ActiveDirectoryConnector.cs index bfedf97..5417f36 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryConnector.cs @@ -239,17 +239,6 @@ public virtual Uid Create(ObjectClass oclass, newDe.Dispose(); } } - - if (!oclass.Equals(ObjectClass.ACCOUNT)) - { - // uid will be the dn for non account objects - String dnUid = nameAttribute.GetNameValue(); - if((dnUid != null) && (dnUid.Length > 0)) - { - dnUid = ActiveDirectoryUtils.NormalizeLdapString(dnUid); - } - return new Uid(dnUid); - } return uid; } @@ -1032,6 +1021,7 @@ public bool SyncHandler(ConnectorObject obj) ConnectorObjectBuilder coBuilder = new ConnectorObjectBuilder(); coBuilder.SetName(obj.Name); coBuilder.SetUid(obj.Uid); + coBuilder.ObjectClass = obj.ObjectClass; coBuilder.AddAttributes(attrs); builder.Object = coBuilder.Build(); @@ -1079,14 +1069,6 @@ public bool SyncHandler(ConnectorObject obj) public virtual void Sync(ObjectClass objClass, SyncToken token, SyncResultsHandler handler, OperationOptions options) { - if (!ObjectClass.ACCOUNT.Equals(objClass)) - { - throw new ConnectorException(_configuration.ConnectorMessages.Format( - "ex_SyncNotAvailable", - "Sync operation is not available for ObjectClass {0}", - objClass.GetObjectClassValue())); - } - String serverName = GetSyncServerName(); ActiveDirectorySyncToken adSyncToken = diff --git a/ActiveDirectoryConnector/CustomAttributeHandlers.cs b/ActiveDirectoryConnector/CustomAttributeHandlers.cs index 0f469ef..882e979 100644 --- a/ActiveDirectoryConnector/CustomAttributeHandlers.cs +++ b/ActiveDirectoryConnector/CustomAttributeHandlers.cs @@ -989,28 +989,17 @@ private ConnectorAttribute GetCaFromDe_OpAtt_Uid( { ICollection value = new List(); - if (ObjectClass.ACCOUNT.Equals(oclass)) - { - // uid is objectGuid - ResultPropertyValueCollection pvc = - searchResult.Properties[ActiveDirectoryConnector.ATT_OBJECT_GUID]; + // uid is objectGuid + ResultPropertyValueCollection pvc = + searchResult.Properties[ActiveDirectoryConnector.ATT_OBJECT_GUID]; - if ((pvc.Count == 1) && (pvc[0] is Byte[])) - { - value.Add(ActiveDirectoryUtils.ConvertUIDBytesToGUIDString((Byte[])pvc[0])); - } - else if (pvc.Count > 1) - { - throw new ConnectorException("There should be only one UID, but multiple values were specified"); - } + if ((pvc.Count == 1) && (pvc[0] is Byte[])) + { + value.Add(ActiveDirectoryUtils.ConvertUIDBytesToGUIDString((Byte[])pvc[0])); } - else + else if (pvc.Count > 1) { - ConnectorAttribute name = GetCaFromDe_OpAtt_Name(oclass, attributeName, searchResult); - if ((name.Value != null) && (name.Value.Count != 0)) - { - value.Add(ActiveDirectoryUtils.NormalizeLdapString((String)name.Value[0])); - } + throw new ConnectorException("There should be only one UID, but multiple values were specified"); } return ConnectorAttributeBuilder.Build(Uid.NAME, value); diff --git a/ActiveDirectoryConnector/ObjectClasses.xml b/ActiveDirectoryConnector/ObjectClasses.xml index 2da8c20..6f858df 100644 --- a/ActiveDirectoryConnector/ObjectClasses.xml +++ b/ActiveDirectoryConnector/ObjectClasses.xml @@ -140,7 +140,11 @@ AttributeInfo name="__ENABLE_DATE__" type="long"/--> - + + + + + @@ -186,6 +190,10 @@ + + + + @@ -222,6 +230,10 @@ + + + + From 514cb4bce03dea5b09070023b4a64972e30dd7a2 Mon Sep 17 00:00:00 2001 From: Gael Allioux Date: Fri, 15 Mar 2013 14:23:40 +0000 Subject: [PATCH 17/33] CR-1427 OPENICF-94 OPENICF-92 --- .../ActiveDirectoryConnector.cs | 73 +------------------ .../ActiveDirectoryUtils.cs | 8 +- ActiveDirectoryConnector/ObjectClasses.xml | 5 +- 3 files changed, 7 insertions(+), 79 deletions(-) diff --git a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs b/ActiveDirectoryConnector/ActiveDirectoryConnector.cs index 5417f36..470c3c5 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryConnector.cs @@ -57,7 +57,7 @@ public enum UpdateType { )] public class ActiveDirectoryConnector : CreateOp, Connector, SchemaOp, DeleteOp, SearchOp, TestOp, UpdateAttributeValuesOp, ScriptOnResourceOp, SyncOp, - AuthenticateOp, AttributeNormalizer, PoolableConnector + AuthenticateOp, PoolableConnector { public static IDictionary> AttributesReturnedByDefault = null; @@ -889,14 +889,6 @@ public virtual Uid Update(UpdateType type, ObjectClass oclass, _utils.UpdateADObject(oclass, updateEntry, attributes, type, _configuration); - if(!ObjectClass.ACCOUNT.Equals(oclass)) { - // other objects use dn as guid for idm backward compatibility - String dnUid = (string)updateEntry.Properties["distinguishedName"][0]; - if ((dnUid != null) && (dnUid.Length > 0)) - { - updatedUid = new Uid(ActiveDirectoryUtils.NormalizeLdapString(dnUid)); - } - } updateEntry.Dispose(); return updatedUid; } @@ -1242,69 +1234,6 @@ public Uid Authenticate(ObjectClass objectClass, string username, #endregion - #region AttributeNormalizer Members - - public virtual ConnectorAttribute NormalizeAttribute(ObjectClass oclass, ConnectorAttribute attribute) - { - // if this gets big, use delegates, but for now, just - // handle individual attributes; - if (attribute is Uid) - { - String uidValue = ((Uid)attribute).GetUidValue(); - // convert to upper case - if (uidValue != null) - { - StringBuilder normalizedUidValue = new StringBuilder(); - - if (oclass.Equals(ObjectClass.ACCOUNT)) - { - // convert to upper case - uidValue = uidValue.ToLower(); - - // now remove spaces - foreach (Char nextChar in uidValue) - { - if (!nextChar.Equals(" ")) - { - normalizedUidValue.Append(nextChar); - } - } - String tempGuid = normalizedUidValue.ToString(); - - return new Uid(tempGuid.Replace("guid", "GUID")); - } - else - { - // the uid is a dn - return new Uid(ActiveDirectoryUtils.NormalizeLdapString(uidValue)); - } - } - else - { - return attribute; - } - } - else if (attribute is Name) - { - String nameValue = ((Name)attribute).GetNameValue(); - return ConnectorAttributeBuilder.Build(attribute.Name, - ActiveDirectoryUtils.NormalizeLdapString(nameValue)); - } - else if (attribute.Name.Equals(PredefinedAttributes.GROUPS_NAME)) - { - IList groupValues = new List(); - foreach(String groupname in attribute.Value) - { - groupValues.Add(ActiveDirectoryUtils.NormalizeLdapString(groupname)); - } - return ConnectorAttributeBuilder.Build(attribute.Name, groupValues); - } - - return attribute; - } - - #endregion - #region PoolableConnector Members public void CheckAlive() diff --git a/ActiveDirectoryConnector/ActiveDirectoryUtils.cs b/ActiveDirectoryConnector/ActiveDirectoryUtils.cs index 0665266..38e5c06 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryUtils.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryUtils.cs @@ -544,7 +544,7 @@ public static String NormalizeLdapString(String ldapString) String[] parts = ldapString.Split(','); for (int i = 0; i < parts.Length; i++) { - normalPath.Append(parts[i].Trim().ToUpper()); + normalPath.Append(parts[i].Trim()); // append a comma after each part (except the last one) if (i < (parts.Length - 1)) { @@ -598,14 +598,14 @@ private static void HandleContainerChange(UpdateType type, String oldContainer = GetParentDn(directoryEntry.Path); String newContainer = GetParentDn(nameAttribute.GetNameValue()); - if (!NormalizeLdapString(oldContainer).Equals(NormalizeLdapString(newContainer))) + if (!NormalizeLdapString(oldContainer).Equals(NormalizeLdapString(newContainer), StringComparison.OrdinalIgnoreCase)) { if (newContainer != null) { try { if (!NormalizeLdapString(oldContainer).Equals( - NormalizeLdapString(newContainer))) + NormalizeLdapString(newContainer), StringComparison.OrdinalIgnoreCase)) { String newContainerLdapPath = ActiveDirectoryUtils.GetLDAPPath( config.LDAPHostName, newContainer); @@ -636,7 +636,7 @@ private static void HandleNameChange(UpdateType type, { String oldName = directoryEntry.Name; String newName = GetRelativeName(nameAttribute); - if (!NormalizeLdapString(oldName).Equals(NormalizeLdapString(newName))) + if (!NormalizeLdapString(oldName).Equals(NormalizeLdapString(newName), StringComparison.OrdinalIgnoreCase)) { directoryEntry.Rename(newName); } diff --git a/ActiveDirectoryConnector/ObjectClasses.xml b/ActiveDirectoryConnector/ObjectClasses.xml index 6f858df..45000e2 100644 --- a/ActiveDirectoryConnector/ObjectClasses.xml +++ b/ActiveDirectoryConnector/ObjectClasses.xml @@ -51,9 +51,7 @@ - - - + @@ -214,6 +212,7 @@ + From 6930086c7fae9ba6491889743d1e26defbd369df Mon Sep 17 00:00:00 2001 From: Gael Allioux Date: Tue, 19 Mar 2013 19:20:56 +0000 Subject: [PATCH 18/33] CR-1443 OPENICF-42 --- ActiveDirectoryConnector/ObjectClasses.xml | 72 ++++++++++++++++++---- 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/ActiveDirectoryConnector/ObjectClasses.xml b/ActiveDirectoryConnector/ObjectClasses.xml index 45000e2..08ebfa2 100644 --- a/ActiveDirectoryConnector/ObjectClasses.xml +++ b/ActiveDirectoryConnector/ObjectClasses.xml @@ -42,12 +42,18 @@ + + + + + + @@ -56,7 +62,10 @@ + + + @@ -64,6 +73,8 @@ + + @@ -116,6 +127,18 @@ + + + + + + + + + + + + @@ -135,7 +158,7 @@ - AttributeInfo name="__ENABLE_DATE__" type="long"/--> + @@ -165,18 +188,16 @@ - - - - + - + + @@ -184,18 +205,28 @@ - - + + + + + + + + + + + + - /> + @@ -213,9 +244,16 @@ + + + + + + + + - - + @@ -233,6 +271,18 @@ + + + + + + + + + + + + From 7d84c23dac4ea4ea98a762c5640b02f28e35ef0d Mon Sep 17 00:00:00 2001 From: Gael Allioux Date: Thu, 21 Mar 2013 11:58:29 +0000 Subject: [PATCH 19/33] RDN attribute should not be CREATABLE/UPDATEABLE --- ActiveDirectoryConnector/ObjectClasses.xml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/ActiveDirectoryConnector/ObjectClasses.xml b/ActiveDirectoryConnector/ObjectClasses.xml index 08ebfa2..616e7dd 100644 --- a/ActiveDirectoryConnector/ObjectClasses.xml +++ b/ActiveDirectoryConnector/ObjectClasses.xml @@ -47,7 +47,10 @@ - + + + + @@ -188,7 +191,10 @@ - + + + + @@ -253,7 +259,8 @@ - + + From 2699af482fbad75c4a6a5db60f2914098c194560 Mon Sep 17 00:00:00 2001 From: Gael Allioux Date: Mon, 25 Mar 2013 11:29:28 +0000 Subject: [PATCH 20/33] Updated Copyright --- ActiveDirectoryConnector/ActiveDirectoryConnector.cs | 2 ++ ActiveDirectoryConnector/ActiveDirectoryUtils.cs | 2 ++ ActiveDirectoryConnector/CustomAttributeHandlers.cs | 2 ++ ActiveDirectoryConnector/ObjectClasses.xml | 2 ++ 4 files changed, 8 insertions(+) diff --git a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs b/ActiveDirectoryConnector/ActiveDirectoryConnector.cs index 470c3c5..74bd21d 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryConnector.cs @@ -19,6 +19,8 @@ * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== + * + * Portions Copyrighted 2012-2013 ForgeRock Inc. */ using System; using System.Reflection; diff --git a/ActiveDirectoryConnector/ActiveDirectoryUtils.cs b/ActiveDirectoryConnector/ActiveDirectoryUtils.cs index 38e5c06..80c30fc 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryUtils.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryUtils.cs @@ -19,6 +19,8 @@ * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== + * + * Portions Copyrighted 2012-2013 ForgeRock Inc. */ using System; using System.Collections.Generic; diff --git a/ActiveDirectoryConnector/CustomAttributeHandlers.cs b/ActiveDirectoryConnector/CustomAttributeHandlers.cs index 882e979..27c957f 100644 --- a/ActiveDirectoryConnector/CustomAttributeHandlers.cs +++ b/ActiveDirectoryConnector/CustomAttributeHandlers.cs @@ -19,6 +19,8 @@ * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== + * + * Portions Copyrighted 2012-2013 ForgeRock Inc. */ using System; using System.Collections.Generic; diff --git a/ActiveDirectoryConnector/ObjectClasses.xml b/ActiveDirectoryConnector/ObjectClasses.xml index 616e7dd..8d1a3c2 100644 --- a/ActiveDirectoryConnector/ObjectClasses.xml +++ b/ActiveDirectoryConnector/ObjectClasses.xml @@ -35,6 +35,8 @@ 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 2013 ForgeRock Inc. --> From dcb1837f09c7a1400f1facbd2b1c75f1504dd35b Mon Sep 17 00:00:00 2001 From: Gael Allioux Date: Fri, 19 Apr 2013 12:46:27 +0000 Subject: [PATCH 21/33] CR-1580 OPENICF-100 fixes compilation issue --- ExchangeConnector/ExchangeConnector.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ExchangeConnector/ExchangeConnector.cs b/ExchangeConnector/ExchangeConnector.cs index 2bb7bc0..a509b69 100644 --- a/ExchangeConnector/ExchangeConnector.cs +++ b/ExchangeConnector/ExchangeConnector.cs @@ -540,10 +540,11 @@ public sealed override void Dispose() /// Object class /// Attribute to be normalized /// Normalized attribute - public override ConnectorAttribute NormalizeAttribute(ObjectClass oclass, ConnectorAttribute attribute) + public ConnectorAttribute NormalizeAttribute(ObjectClass oclass, ConnectorAttribute attribute) + //public override ConnectorAttribute NormalizeAttribute(ObjectClass oclass, ConnectorAttribute attribute) { // normalize the attribute using AD connector first - attribute = base.NormalizeAttribute(oclass, attribute); + //attribute = base.NormalizeAttribute(oclass, attribute); // normalize external mail value if (attribute.Name == AttExternalMail && attribute.Value != null) From 100698588037616be3f636c302aff6b94d354441 Mon Sep 17 00:00:00 2001 From: Laszlo Hordos Date: Tue, 25 Feb 2014 15:58:59 +0000 Subject: [PATCH 22/33] =?UTF-8?q?OPENICF-182=20/=20CR-3097=20=E2=80=93=20U?= =?UTF-8?q?pdate=20the=20AD=20Connector=20to=20use=20OpenICF=201.4=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ActiveDirectoryConfiguration.cs | 2 - .../ActiveDirectoryConnector.cs | 266 +++++++------ .../ActiveDirectoryFilterTranslator.cs | 4 - .../ActiveDirectorySyncToken.cs | 3 - .../ActiveDirectoryUtils.cs | 9 +- .../CustomAttributeHandlers.cs | 72 ++-- .../PasswordChangeHandler.cs | 7 - .../TerminalServicesUtils.cs | 4 - .../UserAccountControl.cs | 4 - ActiveDirectoryConnector/version.template | 2 +- .../ActiveDirectoryConfigurationTests.cs | 6 +- .../ActiveDirectoryConnectorTest.cs | 362 ++++++++++-------- ActiveDirectoryConnectorTests/ConfigHelper.cs | 5 +- .../version.template | 2 +- ExchangeConnector/ExchangeConnector.cs | 99 ++--- ExchangeConnector/RunSpaceInstance.cs | 2 - ExchangeConnector/version.template | 2 +- 17 files changed, 434 insertions(+), 417 deletions(-) diff --git a/ActiveDirectoryConnector/ActiveDirectoryConfiguration.cs b/ActiveDirectoryConnector/ActiveDirectoryConfiguration.cs index 444c41c..e54df96 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryConfiguration.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryConfiguration.cs @@ -21,9 +21,7 @@ * ==================== */ using System; -using System.Collections.Generic; using System.Text; -using System.Diagnostics; using Org.IdentityConnectors.Framework.Spi; using Org.IdentityConnectors.Framework.Common.Exceptions; using Org.IdentityConnectors.Framework.Spi.Operations; diff --git a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs b/ActiveDirectoryConnector/ActiveDirectoryConnector.cs index 74bd21d..0d7ffec 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryConnector.cs @@ -19,48 +19,45 @@ * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== - * - * Portions Copyrighted 2012-2013 ForgeRock Inc. + * Portions Copyrighted 2012-2014 ForgeRock AS. */ using System; using System.Reflection; -using ActiveDs; using System.Collections.Generic; -using System.Collections.ObjectModel; using Org.IdentityConnectors.Common; -using Org.IdentityConnectors.Framework.Api.Operations; using Org.IdentityConnectors.Framework.Spi; using Org.IdentityConnectors.Framework.Spi.Operations; using System.Diagnostics; using Org.IdentityConnectors.Framework.Common.Objects; using Org.IdentityConnectors.Framework.Common.Exceptions; using System.DirectoryServices; +using DS = System.DirectoryServices; using System.DirectoryServices.ActiveDirectory; -using Org.IdentityConnectors.Framework.Common; using System.Text; using Org.IdentityConnectors.Common.Script; using System.Globalization; namespace Org.IdentityConnectors.ActiveDirectory { - public enum UpdateType { + public enum UpdateType + { ADD, DELETE, REPLACE } - - + + /// /// The Active Directory Connector /// [ConnectorClass("connector_displayName", typeof(ActiveDirectoryConfiguration), - MessageCatalogPaths = new String[]{"Org.IdentityConnectors.ActiveDirectory.Messages"} - )] + MessageCatalogPaths = new String[] { "Org.IdentityConnectors.ActiveDirectory.Messages" } + )] public class ActiveDirectoryConnector : CreateOp, Connector, SchemaOp, DeleteOp, - SearchOp, TestOp, UpdateAttributeValuesOp, ScriptOnResourceOp, SyncOp, + SearchOp, TestOp, UpdateAttributeValuesOp, ScriptOnResourceOp, SyncOp, AuthenticateOp, PoolableConnector - { + { public static IDictionary> AttributesReturnedByDefault = null; // special attribute names @@ -111,7 +108,7 @@ public ActiveDirectoryConnector() #region CreateOp Members // implementation of CreateSpiOp - public virtual Uid Create(ObjectClass oclass, + public virtual Uid Create(ObjectClass oclass, ICollection attributes, OperationOptions options) { Uid uid = null; @@ -139,13 +136,13 @@ public virtual Uid Create(ObjectClass oclass, if (nameAttribute == null) { throw new ConnectorException( - _configuration.ConnectorMessages.Format("ex_OperationalAttributeNull", + _configuration.ConnectorMessages.Format("ex_OperationalAttributeNull", "The name operational attribute cannot be null")); } String ldapContainerPath = ActiveDirectoryUtils.GetLDAPPath(_configuration.LDAPHostName, ActiveDirectoryUtils.GetParentDn(nameAttribute.GetNameValue())); - String ldapEntryPath = ActiveDirectoryUtils.GetLDAPPath(_configuration.LDAPHostName, + String ldapEntryPath = ActiveDirectoryUtils.GetLDAPPath(_configuration.LDAPHostName, nameAttribute.GetNameValue()); try @@ -264,7 +261,7 @@ public virtual void Init(Configuration configuration) } string path = GetSearchContainerPath(useGC, _configuration.LDAPHostName, _configuration.Container); Trace.TraceInformation("Search: Getting root node for search"); - _dirHandler = new DirectoryEntry(path,_configuration.DirectoryAdminName, _configuration.DirectoryAdminPassword); + _dirHandler = new DirectoryEntry(path, _configuration.DirectoryAdminName, _configuration.DirectoryAdminPassword); //searcher = new DirectorySearcher(_dirHandler); } @@ -301,7 +298,7 @@ protected ICollection GetDefaultAttributeListForObjectClass( #region SchemaOp Members // implementation of SchemaSpiOp public Schema Schema() - { + { Trace.TraceInformation("Schema method"); if (_schema != null) { @@ -309,12 +306,12 @@ public Schema Schema() return _schema; } - SchemaBuilder schemaBuilder = + SchemaBuilder schemaBuilder = new SchemaBuilder(SafeType.Get(this)); AttributesReturnedByDefault = new Dictionary>(); - + //iterate through supported object classes - foreach(ObjectClass oc in GetSupportedObjectClasses()) + foreach (ObjectClass oc in GetSupportedObjectClasses()) { ObjectClassInfo ocInfo = GetObjectClassInfo(oc); Assertions.NullCheck(ocInfo, "ocInfo"); @@ -323,7 +320,8 @@ public Schema Schema() AttributesReturnedByDefault.Add(oc, new HashSet()); foreach (ConnectorAttributeInfo caInfo in ocInfo.ConnectorAttributeInfos) { - if( caInfo.IsReturnedByDefault ) { + if (caInfo.IsReturnedByDefault) + { AttributesReturnedByDefault[oc].Add(caInfo.Name); } } @@ -336,7 +334,7 @@ public Schema Schema() if (supportedOps != null) { foreach (SafeType op in supportedOps) - { + { schemaBuilder.AddSupportedObjectClass(op, ocInfo); } } @@ -364,11 +362,11 @@ public Schema Schema() /// List of supported object classes protected virtual ICollection GetSupportedObjectClasses() { - IDictionary objectClassInfos = + IDictionary objectClassInfos = CommonUtils.GetOCInfo("Org.IdentityConnectors.ActiveDirectory.ObjectClasses.xml"); return objectClassInfos.Keys; - } + } /// /// Gets the object class info for specified object class, used for schema building @@ -377,7 +375,7 @@ protected virtual ICollection GetSupportedObjectClasses() /// ObjectClass' ObjectClassInfo protected virtual ObjectClassInfo GetObjectClassInfo(ObjectClass oc) { - IDictionary objectClassInfos = + IDictionary objectClassInfos = CommonUtils.GetOCInfo("Org.IdentityConnectors.ActiveDirectory.ObjectClasses.xml"); return objectClassInfos[oc]; @@ -404,7 +402,7 @@ protected virtual IList> GetUnSupportedOperations(ObjectC { return new List> { SafeType.Get(), - SafeType.Get()}; + SafeType.Get()}; } return null; @@ -421,7 +419,7 @@ public virtual Org.IdentityConnectors.Framework.Common.Objects.Filters.FilterTra } // implementation of SearchSpiOp - public virtual void ExecuteQuery(ObjectClass oclass, string query, + public virtual void ExecuteQuery(ObjectClass oclass, string query, ResultsHandler handler, OperationOptions options) { try @@ -432,14 +430,15 @@ public virtual void ExecuteQuery(ObjectClass oclass, string query, useGC = true; } - IDictionarysearchOptions = options.Options; + IDictionary searchOptions = options.Options; SearchScope searchScope = GetADSearchScopeFromOptions(options); string searchContainer = GetADSearchContainerFromOptions(options); // for backward compatibility, support old query style from resource adapters // but log a warning - if((query == null) || (query.Length == 0)) { + if ((query == null) || (query.Length == 0)) + { if ((options != null) && (options.Options != null)) { Object oldStyleQuery = null; @@ -521,7 +520,7 @@ public SearchScope GetADSearchScopeFromOptions(OperationOptions options) // by the SyncSpiOp private void ExecuteQuery(ObjectClass oclass, string query, ResultsHandler handler, OperationOptions options, bool includeDeleted, - SortOption sortOption, string serverName, bool useGlobalCatalog, + SortOption sortOption, string serverName, bool useGlobalCatalog, string searchRoot, SearchScope searchScope) { Trace.TraceInformation("Search: modifying query"); @@ -550,7 +549,7 @@ private void ExecuteQuery(ObjectClass oclass, string query, else { // for backward compatibility ... - if((ObjectClass.ACCOUNT.Equals(oclass)) && (!includeDeleted)) + if ((ObjectClass.ACCOUNT.Equals(oclass)) && (!includeDeleted)) { query = String.Format("(&(ObjectCategory=Person){0})", query); } @@ -598,7 +597,7 @@ private void ExecuteQuery(ObjectClass oclass, string query, try { resultSet = searcher.FindAll(); - foreach (SearchResult result in resultSet) + foreach (DS.SearchResult result in resultSet) { buildConnectorObject(result, oclass, useGlobalCatalog, searchRoot, attributesToReturn, handler); count++; @@ -629,7 +628,7 @@ private void ExecuteQuery(ObjectClass oclass, string query, } - private void buildConnectorObject(SearchResult result, ObjectClass oclass, bool useGlobalCatalog, string searchRoot, ICollection attributesToReturn, ResultsHandler handler) + private void buildConnectorObject(DS.SearchResult result, ObjectClass oclass, bool useGlobalCatalog, string searchRoot, ICollection attributesToReturn, ResultsHandler handler) { try { @@ -653,8 +652,8 @@ private void buildConnectorObject(SearchResult result, ObjectClass oclass, bool // now retrieve the object from a domain controller (dc) // because the gc may not have have all of the attributes, // depending on which attributes are replicated to the gc. - SearchResult savedGcResult = null; - SearchResult savedDcResult = result; + DS.SearchResult savedGcResult = null; + DS.SearchResult savedDcResult = result; if (useGlobalCatalog) { savedGcResult = result; @@ -686,7 +685,7 @@ private void buildConnectorObject(SearchResult result, ObjectClass oclass, bool foreach (string attributeName in attributesToReturn) { - SearchResult savedResults = savedDcResult; + DS.SearchResult savedResults = savedDcResult; // if we are using the global catalog, we had to get the // dc's version of the directory entry, but for usnchanged, // we need the gc version of it @@ -725,7 +724,7 @@ private void buildConnectorObject(SearchResult result, ObjectClass oclass, bool String msg = String.Format("Returning ''{0}''", (result.Path != null) ? result.Path : ""); Trace.TraceInformation(msg); - handler(builder.Build()); + handler.Handle(builder.Build()); } catch (DirectoryServicesCOMException e) { @@ -742,10 +741,10 @@ private void buildConnectorObject(SearchResult result, ObjectClass oclass, bool Trace.TraceWarning(e.Message); } } - + private string GetSearchContainerPath(bool useGC, string hostname, string searchContainer) { - String path; + String path; if (useGC) { @@ -778,7 +777,7 @@ private ICollection GetAttributesToReturn(ObjectClass oclass, OperationO return attributeNames; } - private void AddAttributeIfNotNull(ConnectorObjectBuilder builder, + private void AddAttributeIfNotNull(ConnectorObjectBuilder builder, ConnectorAttribute attribute) { if (attribute != null) @@ -820,52 +819,55 @@ public virtual void Test() try { // see if the Container exists - if (!DirectoryEntry.Exists( GetSearchContainerPath( UseGlobalCatalog(), - _configuration.LDAPHostName, _configuration.Container ) )) + if (!DirectoryEntry.Exists(GetSearchContainerPath(UseGlobalCatalog(), + _configuration.LDAPHostName, _configuration.Container))) { throw new ConnectorException( _configuration.ConnectorMessages.Format( "ex_InvalidContainerInConfiguration", "An invalid container was supplied: {0}", - _configuration.Container ) ); + _configuration.Container)); } } catch (DirectoryServicesCOMException dscex) { - Trace.TraceError( string.Format( CultureInfo.InvariantCulture, - "Failed to determine whether the Container '{0}' exists. Exception: {1}", _configuration.Container, dscex ) ); + Trace.TraceError(string.Format(CultureInfo.InvariantCulture, + "Failed to determine whether the Container '{0}' exists. Exception: {1}", _configuration.Container, dscex)); throw new ConnectorException( _configuration.ConnectorMessages.Format( "ex_ContainerNotFound", "Could not find the Container '{0}', the following message was returned from the server: {1}", - _configuration.Container, dscex.Message ), dscex ); + _configuration.Container, dscex.Message), dscex); } } #endregion #region AdvancedUpdateOp Members - public Uid Update(ObjectClass objclass, Uid uid, ICollection attrs, OperationOptions options) { - return Update(UpdateType.REPLACE,objclass,ConnectorAttributeUtil.AddUid(attrs,uid),options); + public Uid Update(ObjectClass objclass, Uid uid, ICollection attrs, OperationOptions options) + { + return Update(UpdateType.REPLACE, objclass, ConnectorAttributeUtil.AddUid(attrs, uid), options); } - + public Uid AddAttributeValues(ObjectClass objclass, Uid uid, ICollection valuesToAdd, - OperationOptions options) { - return Update(UpdateType.ADD,objclass,ConnectorAttributeUtil.AddUid(valuesToAdd, uid),options); + OperationOptions options) + { + return Update(UpdateType.ADD, objclass, ConnectorAttributeUtil.AddUid(valuesToAdd, uid), options); } - + public Uid RemoveAttributeValues(ObjectClass objclass, Uid uid, ICollection valuesToRemove, - OperationOptions options) { - return Update(UpdateType.DELETE,objclass,ConnectorAttributeUtil.AddUid(valuesToRemove, uid),options); + OperationOptions options) + { + return Update(UpdateType.DELETE, objclass, ConnectorAttributeUtil.AddUid(valuesToRemove, uid), options); } // implementation of AdvancedUpdateSpiOp - public virtual Uid Update(UpdateType type, ObjectClass oclass, + public virtual Uid Update(UpdateType type, ObjectClass oclass, ICollection attributes, OperationOptions options) { Uid updatedUid = null; @@ -883,11 +885,11 @@ public virtual Uid Update(UpdateType type, ObjectClass oclass, throw new ConnectorException(_configuration.ConnectorMessages.Format( "ex_UIDNotPresent", "Uid was not present")); } - + DirectoryEntry updateEntry = ActiveDirectoryUtils.GetDirectoryEntryFromUid(_configuration.LDAPHostName, updatedUid, _configuration.DirectoryAdminName, _configuration.DirectoryAdminPassword); - + _utils.UpdateADObject(oclass, updateEntry, attributes, type, _configuration); @@ -955,14 +957,14 @@ public object RunScriptOnResource(ScriptContext request, OperationOptions option { IDictionary shellArguments = new Dictionary(); String shellPrefix = ""; - if(options.Options.ContainsKey("variablePrefix")) + if (options.Options.ContainsKey("variablePrefix")) { shellPrefix = (string)options.Options["variablePrefix"]; } foreach (String argumentName in arguments.Keys) { - shellArguments.Add((shellPrefix + argumentName), arguments[argumentName]); + shellArguments.Add((shellPrefix + argumentName), arguments[argumentName]); } arguments = shellArguments; @@ -970,14 +972,14 @@ public object RunScriptOnResource(ScriptContext request, OperationOptions option if (options.RunAsUser != null) { arguments.Add("USERNAME", options.RunAsUser); - arguments.Add("PASSWORD", + arguments.Add("PASSWORD", options.RunWithPassword.ToSecureString()); } } - + ScriptExecutorFactory factory = ScriptExecutorFactory.NewInstance(request.ScriptLanguage); - ScriptExecutor executor = factory.NewScriptExecutor(new Assembly[0],request.ScriptText, true); + ScriptExecutor executor = factory.NewScriptExecutor(new Assembly[0], request.ScriptText, true); return executor.Execute(arguments); } @@ -992,80 +994,92 @@ public class SyncResults ActiveDirectorySyncToken _adSyncToken; ActiveDirectoryConfiguration _configuration; - internal SyncResults(SyncResultsHandler syncResultsHandler, - ActiveDirectorySyncToken adSyncToken, ActiveDirectoryConfiguration configuration) { + internal SyncResults(SyncResultsHandler syncResultsHandler, + ActiveDirectorySyncToken adSyncToken, ActiveDirectoryConfiguration configuration) + { _syncResultsHandler = syncResultsHandler; _adSyncToken = adSyncToken; _configuration = configuration; } - public bool SyncHandler(ConnectorObject obj) + public ResultsHandler SyncHandler { - SyncDeltaBuilder builder = new SyncDeltaBuilder(); - ICollection attrs = new HashSet(); - foreach(ConnectorAttribute attribute in obj.GetAttributes()) { - // add all attributes to the object except the - // one used to flag deletes. - if (!attribute.Name.Equals(ATT_IS_DELETED)) - { - attrs.Add(attribute); - } - } - - ConnectorObjectBuilder coBuilder = new ConnectorObjectBuilder(); - coBuilder.SetName(obj.Name); - coBuilder.SetUid(obj.Uid); - coBuilder.ObjectClass = obj.ObjectClass; - coBuilder.AddAttributes(attrs); - builder.Object = coBuilder.Build(); - - ConnectorAttribute tokenAttr = - ConnectorAttributeUtil.Find(ATT_USN_CHANGED, obj.GetAttributes()); - if(tokenAttr == null) { - string msg = _configuration.ConnectorMessages.Format("ex_missingSyncAttribute", - "Attribute {0} is not present in connector object. Cannot proceed with Synchronization", - ATT_USN_CHANGED); - Trace.TraceError(msg); - throw new ConnectorException(msg); - } - long tokenUsnValue = (long)ConnectorAttributeUtil.GetSingleValue(tokenAttr); - - bool? isDeleted = false; - ConnectorAttribute isDeletedAttr = - ConnectorAttributeUtil.Find(ATT_IS_DELETED, obj.GetAttributes()); - if (isDeletedAttr != null) - { - isDeleted = (bool?)ConnectorAttributeUtil.GetSingleValue(isDeletedAttr); - _adSyncToken.LastDeleteUsn = tokenUsnValue; - } - else - { - _adSyncToken.LastModifiedUsn = tokenUsnValue; - } - - builder.Token = _adSyncToken.GetSyncToken(); - - if ((isDeleted != null) && (isDeleted.Equals(true))) - { - builder.DeltaType = SyncDeltaType.DELETE; - } - else + get { - builder.DeltaType = SyncDeltaType.CREATE_OR_UPDATE; + return new ResultsHandler() + { + Handle = obj => + { + SyncDeltaBuilder builder = new SyncDeltaBuilder(); + ICollection attrs = new HashSet(); + foreach (ConnectorAttribute attribute in obj.GetAttributes()) + { + // add all attributes to the object except the + // one used to flag deletes. + if (!attribute.Name.Equals(ATT_IS_DELETED)) + { + attrs.Add(attribute); + } + } + + ConnectorObjectBuilder coBuilder = new ConnectorObjectBuilder(); + coBuilder.SetName(obj.Name); + coBuilder.SetUid(obj.Uid); + coBuilder.ObjectClass = obj.ObjectClass; + coBuilder.AddAttributes(attrs); + builder.Object = coBuilder.Build(); + + ConnectorAttribute tokenAttr = + ConnectorAttributeUtil.Find(ATT_USN_CHANGED, obj.GetAttributes()); + if (tokenAttr == null) + { + string msg = _configuration.ConnectorMessages.Format("ex_missingSyncAttribute", + "Attribute {0} is not present in connector object. Cannot proceed with Synchronization", + ATT_USN_CHANGED); + Trace.TraceError(msg); + throw new ConnectorException(msg); + } + long tokenUsnValue = (long)ConnectorAttributeUtil.GetSingleValue(tokenAttr); + + bool? isDeleted = false; + ConnectorAttribute isDeletedAttr = + ConnectorAttributeUtil.Find(ATT_IS_DELETED, obj.GetAttributes()); + if (isDeletedAttr != null) + { + isDeleted = (bool?)ConnectorAttributeUtil.GetSingleValue(isDeletedAttr); + _adSyncToken.LastDeleteUsn = tokenUsnValue; + } + else + { + _adSyncToken.LastModifiedUsn = tokenUsnValue; + } + + builder.Token = _adSyncToken.GetSyncToken(); + + if ((isDeleted != null) && (isDeleted.Equals(true))) + { + builder.DeltaType = SyncDeltaType.DELETE; + } + else + { + builder.DeltaType = SyncDeltaType.CREATE_OR_UPDATE; + } + + builder.Uid = obj.Uid; + _syncResultsHandler.Handle(builder.Build()); + return true; + } + }; } - - builder.Uid = obj.Uid; - _syncResultsHandler(builder.Build()); - return true; } } - public virtual void Sync(ObjectClass objClass, SyncToken token, + public virtual void Sync(ObjectClass objClass, SyncToken token, SyncResultsHandler handler, OperationOptions options) { String serverName = GetSyncServerName(); - ActiveDirectorySyncToken adSyncToken = + ActiveDirectorySyncToken adSyncToken = new ActiveDirectorySyncToken(token, serverName, UseGlobalCatalog()); string modifiedQuery = GetSyncUpdateQuery(adSyncToken); @@ -1080,7 +1094,7 @@ public virtual void Sync(ObjectClass objClass, SyncToken token, serverName, UseGlobalCatalog(), GetADSearchContainerFromOptions(null), SearchScope.Subtree); // find deleted usn's - DirectoryContext domainContext = new DirectoryContext(DirectoryContextType.DirectoryServer, + DirectoryContext domainContext = new DirectoryContext(DirectoryContextType.DirectoryServer, serverName, _configuration.DirectoryAdminName, _configuration.DirectoryAdminPassword); @@ -1118,7 +1132,7 @@ public virtual SyncToken GetLatestSyncToken(ObjectClass objectClass) highestCommittedUsn = dc.HighestCommittedUsn; } - ActiveDirectorySyncToken token = + ActiveDirectorySyncToken token = new ActiveDirectorySyncToken("", serverName, useGlobalCatalog); token.LastDeleteUsn = highestCommittedUsn; token.LastModifiedUsn = highestCommittedUsn; @@ -1208,8 +1222,8 @@ String GetSyncDeleteQuery(ActiveDirectorySyncToken adSyncToken) #region AuthenticateOp Members - public Uid Authenticate(ObjectClass objectClass, string username, - Org.IdentityConnectors.Common.Security.GuardedString password, + public Uid Authenticate(ObjectClass objectClass, string username, + Org.IdentityConnectors.Common.Security.GuardedString password, OperationOptions options) { bool returnUidOnly = false; diff --git a/ActiveDirectoryConnector/ActiveDirectoryFilterTranslator.cs b/ActiveDirectoryConnector/ActiveDirectoryFilterTranslator.cs index 20b0dc8..8bca95f 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryFilterTranslator.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryFilterTranslator.cs @@ -21,13 +21,9 @@ * ==================== */ using System; -using System.Collections.Generic; -using System.Linq; using System.Text; using Org.IdentityConnectors.Framework.Common.Objects.Filters; using Org.IdentityConnectors.Framework.Common.Objects; -using Org.IdentityConnectors.Common; -using System.Diagnostics; using Org.IdentityConnectors.Framework.Common.Exceptions; namespace Org.IdentityConnectors.ActiveDirectory diff --git a/ActiveDirectoryConnector/ActiveDirectorySyncToken.cs b/ActiveDirectoryConnector/ActiveDirectorySyncToken.cs index 50871f6..ed0c828 100644 --- a/ActiveDirectoryConnector/ActiveDirectorySyncToken.cs +++ b/ActiveDirectoryConnector/ActiveDirectorySyncToken.cs @@ -21,9 +21,6 @@ * ==================== */ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using Org.IdentityConnectors.Framework.Common.Objects; using Org.IdentityConnectors.Framework.Common.Exceptions; diff --git a/ActiveDirectoryConnector/ActiveDirectoryUtils.cs b/ActiveDirectoryConnector/ActiveDirectoryUtils.cs index 80c30fc..8d85d66 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryUtils.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryUtils.cs @@ -19,19 +19,16 @@ * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== - * - * Portions Copyrighted 2012-2013 ForgeRock Inc. + * Portions Copyrighted 2012-2014 ForgeRock AS. */ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using Org.IdentityConnectors.Framework.Common.Objects; using System.DirectoryServices; +using DS = System.DirectoryServices; using Org.IdentityConnectors.Framework.Common.Exceptions; using System.Diagnostics; -using Org.IdentityConnectors.Framework.Common; -using Org.IdentityConnectors.Framework.Spi.Operations; using System.Security; using ActiveDs; using Org.IdentityConnectors.Common.Security; @@ -328,7 +325,7 @@ internal void UpdateADObject(ObjectClass oclass, } internal ConnectorAttribute GetConnectorAttributeFromADEntry(ObjectClass oclass, - String attributeName, SearchResult searchResult) + String attributeName, DS.SearchResult searchResult) { // Boolean translated = false; if (searchResult == null) diff --git a/ActiveDirectoryConnector/CustomAttributeHandlers.cs b/ActiveDirectoryConnector/CustomAttributeHandlers.cs index 27c957f..8eafb7c 100644 --- a/ActiveDirectoryConnector/CustomAttributeHandlers.cs +++ b/ActiveDirectoryConnector/CustomAttributeHandlers.cs @@ -19,20 +19,16 @@ * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== - * - * Portions Copyrighted 2012-2013 ForgeRock Inc. + * Portions Copyrighted 2012-2014 ForgeRock AS. */ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Security; using Org.IdentityConnectors.Framework.Common.Objects; using Org.IdentityConnectors.Framework.Common; -using Org.IdentityConnectors.Framework.Spi.Operations; using System.DirectoryServices; +using DS = System.DirectoryServices; using Org.IdentityConnectors.Framework.Common.Exceptions; -using Org.IdentityConnectors.Common.Security; using System.Diagnostics; using ActiveDs; using System.IO; @@ -275,7 +271,7 @@ internal void UpdateDeFromCa(ObjectClass oclass, internal ConnectorAttribute GetCaFromDe(ObjectClass oclass, - string attributeName, SearchResult searchResult) + string attributeName, DS.SearchResult searchResult) { ConnectorAttribute attribute = null; @@ -300,7 +296,7 @@ internal delegate void UpdateDeFromCa_delegate(ObjectClass oclass, ConnectorAttribute attribute); internal delegate ConnectorAttribute GetCaFromDe_delegate(ObjectClass oclass, - string attributeName, SearchResult searchResult); + string attributeName, DS.SearchResult searchResult); public void GetAddsAndDeletes(ICollectionvaluesToAdd, ICollectionvaluesToRemove, PropertyValueCollection oldValues, ICollectionnewValues, UpdateType type) { @@ -802,7 +798,7 @@ internal void UpdateDeFromCa_Att_Generic(ObjectClass oclass, #region GetCaFromDe Handlers private ConnectorAttribute GetCaFromDe_Att_Generic( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { ConnectorAttributeBuilder attributeBuilder = new ConnectorAttributeBuilder(); @@ -847,7 +843,7 @@ private ConnectorAttribute GetCaFromDe_Att_Generic( } private ConnectorAttribute GetCaFromDe_OpAtt_GroupMembers( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { ConnectorAttributeBuilder attributeBuilder = new ConnectorAttributeBuilder(); @@ -899,7 +895,7 @@ private ConnectorAttribute GetCaFromDe_OpAtt_GroupMembers( } searcher.PropertiesToLoad.Clear(); searcher.PropertiesToLoad.Add(memberRange); - SearchResult sresult = searcher.FindOne(); + DS.SearchResult sresult = searcher.FindOne(); if (sresult.Properties.Contains(memberRange)) { foreach (object valueObject in sresult.Properties[memberRange]) @@ -968,7 +964,7 @@ private ConnectorAttribute GetCaFromDe_OpAtt_GroupMembers( return attributeBuilder.Build(); } private ConnectorAttribute GetCaFromDe_OpAtt_Name( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { String value = null; ResultPropertyValueCollection pvc = null; @@ -987,7 +983,7 @@ private ConnectorAttribute GetCaFromDe_OpAtt_Name( } private ConnectorAttribute GetCaFromDe_OpAtt_Uid( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { ICollection value = new List(); @@ -1008,7 +1004,7 @@ private ConnectorAttribute GetCaFromDe_OpAtt_Uid( } private ConnectorAttribute GetCaFromDe_Att_Container( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { if (searchResult == null) { @@ -1029,7 +1025,7 @@ private ConnectorAttribute GetCaFromDe_Att_Container( } private ConnectorAttribute GetCaFromDe_OpAtt_Groups( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { ConnectorAttribute realAttribute = GetCaFromDe_Att_Generic( oclass, ActiveDirectoryConnector.ATT_MEMBEROF, searchResult); @@ -1045,7 +1041,7 @@ private ConnectorAttribute GetCaFromDe_OpAtt_Groups( } private ConnectorAttribute GetCaFromDe_OpAtt_Accounts( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { ConnectorAttribute realAttribute = GetCaFromDe_Att_Generic( oclass, ActiveDirectoryConnector.ATT_MEMBER, searchResult); @@ -1061,7 +1057,7 @@ private ConnectorAttribute GetCaFromDe_OpAtt_Accounts( } private ConnectorAttribute GetCaFromDe_OpAtt_Enabled( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { if (searchResult == null) { @@ -1076,7 +1072,7 @@ private ConnectorAttribute GetCaFromDe_OpAtt_Enabled( } private ConnectorAttribute GetCaFromDe_OpAtt_PasswordExpired( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { ConnectorAttribute realAttribute = GetCaFromDe_Att_Generic( oclass, ActiveDirectoryConnector.ATT_PWD_LAST_SET, searchResult); @@ -1096,7 +1092,7 @@ private ConnectorAttribute GetCaFromDe_OpAtt_PasswordExpired( } private ConnectorAttribute GetCaFromDe_OpAtt_Description( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { ConnectorAttribute realDescription = GetCaFromDe_Att_Generic( oclass, ActiveDirectoryConnector.ATT_DESCRIPTION, searchResult); @@ -1114,7 +1110,7 @@ private ConnectorAttribute GetCaFromDe_OpAtt_Description( } private ConnectorAttribute GetCaFromDe_OpAtt_ShortName( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { ConnectorAttribute realShortName = GetCaFromDe_Att_Generic( oclass, ActiveDirectoryConnector.ATT_SHORT_NAME, searchResult); @@ -1132,7 +1128,7 @@ private ConnectorAttribute GetCaFromDe_OpAtt_ShortName( } private ConnectorAttribute GetCaFromDe_OpAtt_PasswordExpireDate( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { // get the value from ad ConnectorAttribute accountExpireAttribute = GetCaFromDe_Att_Generic( @@ -1157,7 +1153,7 @@ private ConnectorAttribute GetCaFromDe_OpAtt_PasswordExpireDate( } private ConnectorAttribute GetCaFromDe_OpAtt_Lockout( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { bool locked = false; @@ -1177,7 +1173,7 @@ private ConnectorAttribute GetCaFromDe_OpAtt_Lockout( } private ConnectorAttribute GetCaFromDe_PasswordNeverExpires( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { ConnectorAttribute ca = null; DirectoryEntry de = searchResult.GetDirectoryEntry(); @@ -1233,14 +1229,14 @@ private ConnectorAttribute GetCaFromDe_OpAtt_DisableDate( */ private ConnectorAttribute GetCaFromDe_Att_TSInitialProgram( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { return ReturnConnectorAttribute(TerminalServicesUtils.TS_INITIAL_PROGRAM, TerminalServicesUtils.GetInitialProgram(searchResult)); } private ConnectorAttribute GetCaFromDe_Att_TSInitalProgramDir( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { return ReturnConnectorAttribute(TerminalServicesUtils.TS_INITIAL_PROGRAM_DIR, TerminalServicesUtils.GetInitialProgramDir(searchResult)); @@ -1248,42 +1244,42 @@ private ConnectorAttribute GetCaFromDe_Att_TSInitalProgramDir( private ConnectorAttribute GetCaFromDe_Att_TSAllowLogon( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { return ReturnConnectorAttribute(TerminalServicesUtils.TS_ALLOW_LOGON, TerminalServicesUtils.GetAllowLogon(searchResult)); } private ConnectorAttribute GetCaFromDe_Att_TSMaxConnectionTime( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { return ReturnConnectorAttribute(TerminalServicesUtils.TS_MAX_CONNECTION_TIME, TerminalServicesUtils.GetMaxConnectionTime(searchResult)); } private ConnectorAttribute GetCaFromDe_Att_TSMaxDisconnectionTime( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { return ReturnConnectorAttribute(TerminalServicesUtils.TS_MAX_DISCONNECTION_TIME, TerminalServicesUtils.GetMaxDisconnectionTime(searchResult)); } private ConnectorAttribute GetCaFromDe_Att_TSMaxIdleTime( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { return ReturnConnectorAttribute(TerminalServicesUtils.TS_MAX_IDLE_TIME, TerminalServicesUtils.GetMaxIdleTime(searchResult)); } private ConnectorAttribute GetCaFromDe_Att_TSConnectClientDrivesAtLogon( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { return ReturnConnectorAttribute(TerminalServicesUtils.TS_CONNECT_CLIENT_DRIVES_AT_LOGON, TerminalServicesUtils.GetConnectClientDrivesAtLogon(searchResult)); } private ConnectorAttribute GetCaFromDe_Att_TSConnectClientPrintersAtLogon( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { return ReturnConnectorAttribute( TerminalServicesUtils.TS_CONNECT_CLIENT_PRINTERS_AT_LOGON, @@ -1291,7 +1287,7 @@ private ConnectorAttribute GetCaFromDe_Att_TSConnectClientPrintersAtLogon( } private ConnectorAttribute GetCaFromDe_Att_TSDefaultToMainPrinter( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { return ReturnConnectorAttribute( TerminalServicesUtils.TS_DEFAULT_TO_MAIN_PRINTER, @@ -1299,7 +1295,7 @@ private ConnectorAttribute GetCaFromDe_Att_TSDefaultToMainPrinter( } private ConnectorAttribute GetCaFromDe_Att_TSBrokenConnectionAction( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { return ReturnConnectorAttribute( TerminalServicesUtils.TS_BROKEN_CONNECTION_ACTION, @@ -1307,33 +1303,33 @@ private ConnectorAttribute GetCaFromDe_Att_TSBrokenConnectionAction( } private ConnectorAttribute GetCaFromDe_Att_TSReconnectionAction( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { return ReturnConnectorAttribute(TerminalServicesUtils.TS_RECONNECTION_ACTION, TerminalServicesUtils.GetReconnectionAction(searchResult)); } private ConnectorAttribute GetCaFromDe_Att_TSEnableRemoteControl( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { return ReturnConnectorAttribute(TerminalServicesUtils.TS_ENABLE_REMOTE_CONTROL, TerminalServicesUtils.GetEnableRemoteControl(searchResult)); } private ConnectorAttribute GetCaFromDe_Att_TSProfilePath( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { return ReturnConnectorAttribute(TerminalServicesUtils.TS_PROFILE_PATH, TerminalServicesUtils.GetProfilePath(searchResult)); } private ConnectorAttribute GetCaFromDe_Att_TSHomeDirectory( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { return ReturnConnectorAttribute(TerminalServicesUtils.TS_HOME_DIRECTORY, TerminalServicesUtils.GetHomeDirectory(searchResult)); } private ConnectorAttribute GetCaFromDe_Att_TSHomeDrive( - ObjectClass oclass, string attributeName, SearchResult searchResult) + ObjectClass oclass, string attributeName, DS.SearchResult searchResult) { return ReturnConnectorAttribute(TerminalServicesUtils.TS_HOME_DRIVE, TerminalServicesUtils.GetHomeDrive(searchResult)); diff --git a/ActiveDirectoryConnector/PasswordChangeHandler.cs b/ActiveDirectoryConnector/PasswordChangeHandler.cs index 1e62682..580b0a3 100644 --- a/ActiveDirectoryConnector/PasswordChangeHandler.cs +++ b/ActiveDirectoryConnector/PasswordChangeHandler.cs @@ -21,19 +21,12 @@ * ==================== */ using System; -using System.Collections.Generic; using System.Diagnostics; -using System.DirectoryServices.Protocols; -using System.Linq; -using System.Net; using System.Security.Permissions; -using System.Text; using System.DirectoryServices; using Org.IdentityConnectors.Common.Security; using ActiveDs; using Org.IdentityConnectors.Framework.Common.Exceptions; -using System.DirectoryServices.AccountManagement; -using System.DirectoryServices.ActiveDirectory; using System.Threading; using Org.IdentityConnectors.Framework.Common.Objects; using System.Security.Principal; diff --git a/ActiveDirectoryConnector/TerminalServicesUtils.cs b/ActiveDirectoryConnector/TerminalServicesUtils.cs index 29aad13..e2fb705 100644 --- a/ActiveDirectoryConnector/TerminalServicesUtils.cs +++ b/ActiveDirectoryConnector/TerminalServicesUtils.cs @@ -21,12 +21,8 @@ * ==================== */ using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Text; using System.DirectoryServices; -using Org.IdentityConnectors.Framework.Spi.Operations; using Org.IdentityConnectors.Framework.Common.Exceptions; namespace Org.IdentityConnectors.ActiveDirectory diff --git a/ActiveDirectoryConnector/UserAccountControl.cs b/ActiveDirectoryConnector/UserAccountControl.cs index 476359f..d9131af 100644 --- a/ActiveDirectoryConnector/UserAccountControl.cs +++ b/ActiveDirectoryConnector/UserAccountControl.cs @@ -21,11 +21,7 @@ * ==================== */ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.DirectoryServices; -using Org.IdentityConnectors.Framework.Common.Exceptions; namespace Org.IdentityConnectors.ActiveDirectory { diff --git a/ActiveDirectoryConnector/version.template b/ActiveDirectoryConnector/version.template index bd2666a..77d55b2 100644 --- a/ActiveDirectoryConnector/version.template +++ b/ActiveDirectoryConnector/version.template @@ -1 +1 @@ -1.0.0.0 \ No newline at end of file +1.4.0.0 \ No newline at end of file diff --git a/ActiveDirectoryConnectorTests/ActiveDirectoryConfigurationTests.cs b/ActiveDirectoryConnectorTests/ActiveDirectoryConfigurationTests.cs index de953c8..23ff7af 100644 --- a/ActiveDirectoryConnectorTests/ActiveDirectoryConfigurationTests.cs +++ b/ActiveDirectoryConnectorTests/ActiveDirectoryConfigurationTests.cs @@ -19,11 +19,9 @@ * 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.Collections.Generic; -using System.Linq; -using System.Text; + using NUnit.Framework; using Org.IdentityConnectors.Test.Common; using Org.IdentityConnectors.Framework.Common.Exceptions; diff --git a/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTest.cs b/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTest.cs index 2fed782..01d29b6 100644 --- a/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTest.cs +++ b/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTest.cs @@ -19,6 +19,7 @@ * 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.Collections.Generic; @@ -42,9 +43,9 @@ namespace Org.IdentityConnectors.ActiveDirectory [TestFixture] public class ActiveDirectoryConnectorTest { - Random _rand = new Random(); - - + Random _rand = new Random(); + + // having troubles with duplicate random numbers public static List randomList = new List(); @@ -64,7 +65,7 @@ public void TestTest() connectorBad.Init(config); connectorBad.Test(); - Assert.Fail( "Bad configuration should have caused an exception" ); + Assert.Fail("Bad configuration should have caused an exception"); } catch (ConnectorException e) { @@ -76,10 +77,10 @@ public void TestTest() { config.Container += ",DC=BadDC"; ActiveDirectoryConnector connectorBad = new ActiveDirectoryConnector(); - connectorBad.Init( config ); + connectorBad.Init(config); connectorBad.Test(); - Assert.Fail( "Configuration with bad DC in Container should have caused an exception" ); + Assert.Fail("Configuration with bad DC in Container should have caused an exception"); } catch (ConnectorException e) { @@ -91,7 +92,7 @@ public void TestTest() public void TestSchema() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Schema schema = connector.Schema(); Boolean foundOptionalAttributes = false; Boolean foundOperationalAttributes = false; @@ -101,10 +102,11 @@ public void TestSchema() // should be null. Group and account should have some operational // attributes Assert.AreEqual(3, schema.ObjectClassInfo.Count); - foreach(ObjectClassInfo ocInfo in schema.ObjectClassInfo) { + foreach (ObjectClassInfo ocInfo in schema.ObjectClassInfo) + { Assert.IsNotNull(ocInfo); Assert.That((ocInfo.ObjectType == ObjectClass.ACCOUNT.GetObjectClassValue()) - || (ocInfo.ObjectType == ActiveDirectoryConnector.OBJECTCLASS_GROUP) + || (ocInfo.ObjectType == ActiveDirectoryConnector.OBJECTCLASS_GROUP) || (ocInfo.ObjectType == ActiveDirectoryConnector.OBJECTCLASS_OU)); Trace.WriteLine("****** " + ocInfo.ObjectType); @@ -115,20 +117,23 @@ public void TestSchema() } foreach (ConnectorAttributeInfo caInfo in ocInfo.ConnectorAttributeInfos) - { + { Assert.IsNotNull(caInfo); - Trace.WriteLine(String.Format("{0} {1} {2} {3}", caInfo.Name, + Trace.WriteLine(String.Format("{0} {1} {2} {3}", caInfo.Name, caInfo.IsCreatable ? "createable" : "", caInfo.IsUpdateable ? "updateable" : "", caInfo.IsRequired ? "required" : "", caInfo.IsMultiValued ? "multivalue" : "")); - if(ConnectorAttributeUtil.IsSpecial(caInfo)) { + if (ConnectorAttributeUtil.IsSpecial(caInfo)) + { foundOperationalAttributes = true; - } else { + } + else + { if (!caInfo.IsRequired) { foundOptionalAttributes = true; - } + } } } Assert.That(foundOperationalAttributes && foundOptionalAttributes); @@ -142,7 +147,7 @@ public void TestBasics_Account() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); // create user ICollection createAttributes = GetNormalAttributes_Account(); @@ -154,7 +159,7 @@ public void TestBasics_Account() new List(); Name oldName = ConnectorAttributeUtil.GetNameFromAttributes(createAttributes); String newName = ActiveDirectoryUtils.GetRelativeName(oldName); - newName = newName.Trim() + "_new, " + GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ); + newName = newName.Trim() + "_new, " + GetProperty(ConfigHelper.CONFIG_PROPERTY_CONTAINER); updateReplaceAttrs.Add(ConnectorAttributeBuilder.Build( Name.NAME, newName)); updateReplaceAttrs.Add(ConnectorAttributeBuilder.Build( @@ -182,7 +187,7 @@ public void TestBasics_Group() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid uidToDelete = null; try @@ -211,7 +216,7 @@ public void TestBasics_Group() new List(); Name oldName = ConnectorAttributeUtil.GetNameFromAttributes(createAttributes); String newName = ActiveDirectoryUtils.GetRelativeName(oldName); - newName = newName.Trim() + "_new, " + GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ); + newName = newName.Trim() + "_new, " + GetProperty(ConfigHelper.CONFIG_PROPERTY_CONTAINER); updateReplaceAttrs.Add(createUid); updateReplaceAttrs.Add(ConnectorAttributeBuilder.Build( @@ -246,7 +251,7 @@ public void TestCreate_Account() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid createUid = null; try { @@ -269,7 +274,7 @@ public void TestCreate_Group() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid createUid = null; try { @@ -292,12 +297,12 @@ public void TestCreate_OrganizationalUnit() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid createUid = null; try { ICollection createAttributes = GetNormalAttributes_OrganizationalUnit(); - createUid = CreateAndVerifyObject(connector, + createUid = CreateAndVerifyObject(connector, ActiveDirectoryConnector.ouObjectClass, createAttributes); } finally @@ -327,7 +332,7 @@ public void TestCreateWithHomeDirectory_Account() ICollection createAttributes = GetNormalAttributes_Account(); // read the homedir path, and append the samaccountname - StringBuilder homeDirPathBuilder = new StringBuilder( GetProperty( ConfigHelper.TEST_PARAM_SHARED_HOME_FOLDER ) ); + StringBuilder homeDirPathBuilder = new StringBuilder(GetProperty(ConfigHelper.TEST_PARAM_SHARED_HOME_FOLDER)); if (!homeDirPathBuilder.ToString().EndsWith("\\")) { homeDirPathBuilder.Append('\\'); @@ -419,7 +424,7 @@ public void TestCreateWithHomeDirectoryNoCreateConfig_Account() ICollection createAttributes = GetNormalAttributes_Account(); // read the homedir path, and append the samaccountname - StringBuilder homeDirPathBuilder = new StringBuilder( GetProperty( ConfigHelper.TEST_PARAM_SHARED_HOME_FOLDER ) ); + StringBuilder homeDirPathBuilder = new StringBuilder(GetProperty(ConfigHelper.TEST_PARAM_SHARED_HOME_FOLDER)); if (!homeDirPathBuilder.ToString().EndsWith("\\")) { homeDirPathBuilder.Append('\\'); @@ -469,7 +474,7 @@ public void TestSearchNoFilter_Account() int numCreated = 0; for (numCreated = 0; numCreated < 5; numCreated++) { - createdUids.Add(CreateAndVerifyObject(connector, + createdUids.Add(CreateAndVerifyObject(connector, ObjectClass.ACCOUNT, GetNormalAttributes_Account())); } @@ -517,7 +522,7 @@ public void TestSearchNoFilter_Account() public void TestSearchNoFilter_Group() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); ICollection createdUids = new HashSet(); try @@ -574,7 +579,7 @@ public void TestSearchNoFilter_Group() public void TestSearchByName_account() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid createUid = null; @@ -584,7 +589,7 @@ public void TestSearchByName_account() GetNormalAttributes_Account()); // find out what the name was - ConnectorObject newObject = GetConnectorObjectFromUid(connector, + ConnectorObject newObject = GetConnectorObjectFromUid(connector, ObjectClass.ACCOUNT, createUid); Name nameAttr = newObject.Name; Assert.IsNotNull(nameAttr); @@ -645,7 +650,7 @@ public void TestSearchByName_account() public void TestSearchByName_group() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid createUid = null; @@ -716,7 +721,7 @@ public void TestSearchByName_group() public void TestSearchByCNWithWildcard_account() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid uid1 = null; Uid uid2 = null; @@ -764,7 +769,7 @@ public void TestSearchByCNWithWildcard_account() public void TestSearchByRegularAttribute_account() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid createUid = null; @@ -818,7 +823,7 @@ public void TestSearchByRegularAttribute_account() public void TestSearchByRegularAttributeWithWildcard_account() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); ICollection uids = new HashSet(); @@ -883,7 +888,7 @@ public void TestCreateWithAllAttributes_Account() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid createUid = null; try @@ -910,7 +915,7 @@ public void Test_OpAtt_Enabled_Account() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid createUid = null; try @@ -944,15 +949,15 @@ public void TestScriptOnResource() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); try { RunScript(connector, "", "", ""); - RunScript( connector, GetProperty( ConfigHelper.CONFIG_PROPERTY_SCRIPT_USER_LOCAL ), - GetProperty( ConfigHelper.CONFIG_PROPERTY_SCRIPT_PASSWORD_LOCAL ), "" ); - RunScript( connector, GetProperty( ConfigHelper.CONFIG_PROPERTY_SCRIPT_USER_DOMAIN ), - GetProperty( ConfigHelper.CONFIG_PROPERTY_SCRIPT_PASSWORD_DOMAIN ), "" ); + RunScript(connector, GetProperty(ConfigHelper.CONFIG_PROPERTY_SCRIPT_USER_LOCAL), + GetProperty(ConfigHelper.CONFIG_PROPERTY_SCRIPT_PASSWORD_LOCAL), ""); + RunScript(connector, GetProperty(ConfigHelper.CONFIG_PROPERTY_SCRIPT_USER_DOMAIN), + GetProperty(ConfigHelper.CONFIG_PROPERTY_SCRIPT_PASSWORD_DOMAIN), ""); // now try one with the prefix set ActiveDirectoryConfiguration prefixConfig = (ActiveDirectoryConfiguration)ConfigHelper.GetConfiguration(); @@ -966,7 +971,7 @@ public void TestScriptOnResource() bool scriptFailed = false; try { - RunScript( connector, GetProperty( ConfigHelper.CONFIG_PROPERTY_USER ), "bogus", "" ); + RunScript(connector, GetProperty(ConfigHelper.CONFIG_PROPERTY_USER), "bogus", ""); } catch (Exception e) { @@ -984,10 +989,10 @@ public void TestAddGroup_Account() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid groupUid = null; Uid userUid = null; - try + try { userUid = CreateAndVerifyObject(connector, ObjectClass.ACCOUNT, GetNormalAttributes_Account()); @@ -996,7 +1001,7 @@ public void TestAddGroup_Account() TestHelpers.SearchToList(connector, ObjectClass.ACCOUNT, userUidFilter); Assert.AreEqual(1, foundUserObjects.Count); - groupUid = CreateAndVerifyObject(connector, + groupUid = CreateAndVerifyObject(connector, ActiveDirectoryConnector.groupObjectClass, GetNormalAttributes_Group()); Filter groupUidFilter = FilterBuilder.EqualTo(groupUid); IList foundGroupObjects = @@ -1010,10 +1015,12 @@ public void TestAddGroup_Account() ICollection attributesToGet = GetDefaultAttributesToGet(ObjectClass.ACCOUNT); attributesToGet.Add(PredefinedAttributes.GROUPS_NAME); optionsBuilder.AttributesToGet = attributesToGet.ToArray(); - UpdateAddAndVerifyUser(connector, ObjectClass.ACCOUNT, + UpdateAddAndVerifyUser(connector, ObjectClass.ACCOUNT, userUid, modifiedAttrs, optionsBuilder.Build()); - } finally { + } + finally + { DeleteAndVerifyObject(connector, ObjectClass.ACCOUNT, userUid, false, false); DeleteAndVerifyObject(connector, ActiveDirectoryConnector.groupObjectClass, groupUid, false, false); } @@ -1023,7 +1030,7 @@ public void TestAddGroup_Account() public void TestRemoveAttributeValue() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid createUid = null; @@ -1033,7 +1040,7 @@ public void TestRemoveAttributeValue() ICollection attributes = new HashSet(); attributes.Add(ConnectorAttributeBuilder.Build( - "ad_container", GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ) ) ); + "ad_container", GetProperty(ConfigHelper.CONFIG_PROPERTY_CONTAINER))); attributes.Add(ConnectorAttributeBuilder.Build( "userPassword", "secret")); attributes.Add(ConnectorAttributeBuilder.Build( @@ -1046,12 +1053,12 @@ public void TestRemoveAttributeValue() "displayName", "nunit test user " + randomNumber)); attributes.Add(ConnectorAttributeBuilder.Build( Name.NAME, "cn=nunit" + randomNumber + "," + - GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ) ) ); + GetProperty(ConfigHelper.CONFIG_PROPERTY_CONTAINER))); attributes.Add(ConnectorAttributeBuilder.Build( "mail", "nunitUser" + randomNumber + "@some.com")); attributes.Add(ConnectorAttributeBuilder.Build( "otherHomePhone", "512.555.1212", "512.123.4567")); - + createUid = CreateAndVerifyObject(connector, ObjectClass.ACCOUNT, attributes); @@ -1086,12 +1093,13 @@ public void TestRemoveAttributeValue() public void TestContainerChange_account() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid createOuUid = null; Uid createUserUid = null; - try { + try + { // create container for this test ICollection ouAttributes = GetNormalAttributes_OrganizationalUnit(); createOuUid = CreateAndVerifyObject(connector, @@ -1129,8 +1137,8 @@ public void TestContainerChange_account() String lhs = ActiveDirectoryUtils.NormalizeLdapString(ouPath); String rhs = ActiveDirectoryUtils.NormalizeLdapString(ConnectorAttributeUtil.GetStringValue(foundContainerAttr)); Assert.AreEqual(lhs, rhs); - } - finally + } + finally { if (createUserUid != null) { @@ -1152,13 +1160,14 @@ public void TestContainerChange_account() public void TestContainerChange_group() { ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid createOuUid = null; Uid createGroupUid = null; Uid updateGroupUid = null; - try { + try + { // create container for this test ICollection ouAttributes = GetNormalAttributes_OrganizationalUnit(); createOuUid = CreateAndVerifyObject(connector, @@ -1184,7 +1193,7 @@ public void TestContainerChange_group() updateAttrs.Add(new Name(newName)); updateAttrs.Add(createGroupUid); - updateGroupUid = connector.Update(UpdateType.REPLACE, + updateGroupUid = connector.Update(UpdateType.REPLACE, ActiveDirectoryConnector.groupObjectClass, updateAttrs, null); ICollection results = TestHelpers.SearchToList( @@ -1197,15 +1206,16 @@ public void TestContainerChange_group() String lhs = ActiveDirectoryUtils.NormalizeLdapString(ouPath); String rhs = ActiveDirectoryUtils.NormalizeLdapString(ConnectorAttributeUtil.GetStringValue(foundContainerAttr)); Assert.AreEqual(lhs, rhs); - } - finally + } + finally { - if(updateGroupUid != null) + if (updateGroupUid != null) { //remove the one. if we updated, this is the id DeleteAndVerifyObject(connector, ActiveDirectoryConnector.groupObjectClass, updateGroupUid, false, true); - } else if (createGroupUid != null) + } + else if (createGroupUid != null) { //remove the one. if we didn't update, this is the id DeleteAndVerifyObject(connector, ActiveDirectoryConnector.groupObjectClass, @@ -1227,7 +1237,7 @@ public void TestEnableDate() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid createUid = null; try @@ -1262,7 +1272,7 @@ public void TestDisableDate() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid createUid = null; try @@ -1300,8 +1310,8 @@ public void TestDisableDate() public void TestSyncGC() { // test with searchChildDomain (uses GC) - TestSync( true, GetProperty( ConfigHelper.config_PROPERTY_SYNC_CONTAINER_ROOT, null ) ); - TestSync( true, GetProperty( ConfigHelper.config_PROPERTY_SYNC_CONTAINER_CHILD, null ) ); + TestSync(true, GetProperty(ConfigHelper.config_PROPERTY_SYNC_CONTAINER_ROOT, null)); + TestSync(true, GetProperty(ConfigHelper.config_PROPERTY_SYNC_CONTAINER_CHILD, null)); } // test sync @@ -1309,8 +1319,8 @@ public void TestSyncGC() public void TestSyncDC() { // test withouth searchChildDomains (uses DC) - TestSync( false, GetProperty( ConfigHelper.config_PROPERTY_SYNC_CONTAINER_ROOT, null ) ); - TestSync( false, GetProperty( ConfigHelper.config_PROPERTY_SYNC_CONTAINER_CHILD, null ) ); + TestSync(false, GetProperty(ConfigHelper.config_PROPERTY_SYNC_CONTAINER_ROOT, null)); + TestSync(false, GetProperty(ConfigHelper.config_PROPERTY_SYNC_CONTAINER_CHILD, null)); } [Test] @@ -1318,7 +1328,7 @@ public void TestUserPasswordChange() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid createUid = null; try @@ -1406,7 +1416,7 @@ public void TestAuthenticateUser() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid createUid = null; try @@ -1425,7 +1435,7 @@ public void TestAuthenticateUser() Uid authUid = connector.Authenticate(ObjectClass.ACCOUNT, ConnectorAttributeUtil.GetAsStringValue(ConnectorAttributeUtil.Find("sAMAccountName", createAttributes)), gsCurrentPassword, null); - + Assert.AreEqual(createUid, authUid); // make sure authenticate fails - wrong password @@ -1440,7 +1450,7 @@ public void TestAuthenticateUser() catch (InvalidCredentialException e) { caughtException = true; - } + } Assert.IsTrue(caughtException, "Negative test case should throw InvalidCredentialsException"); // change password @@ -1459,10 +1469,11 @@ public void TestAuthenticateUser() // make sure it fails with the wrong password caughtException = false; - try { - connector.Authenticate(ObjectClass.ACCOUNT, - ConnectorAttributeUtil.GetAsStringValue(ConnectorAttributeUtil.Find("sAMAccountName", createAttributes)), - GetGuardedString("bogusPassword"), null); + try + { + connector.Authenticate(ObjectClass.ACCOUNT, + ConnectorAttributeUtil.GetAsStringValue(ConnectorAttributeUtil.Find("sAMAccountName", createAttributes)), + GetGuardedString("bogusPassword"), null); } catch (Exception e) { @@ -1524,7 +1535,7 @@ public void TestShortnameAndDescription() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid uidAccount = null; Uid uidGroup = null; Uid uidOu = null; @@ -1654,7 +1665,7 @@ public void TestPasswordExpiration() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid createUid = null; try @@ -1736,7 +1747,7 @@ public void TestAccountLocked() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid createUid = null; try @@ -1766,7 +1777,7 @@ public void TestAccountLocked() ConnectorAttributeUtil.GetAsStringValue(ConnectorAttributeUtil.Find("sAMAccountName", createAttributes)), GetGuardedString("bogusPassword"), null); } - catch(Exception e) + catch (Exception e) { } @@ -1892,7 +1903,7 @@ public void TestSync(bool searchChildDomains, String container) connector.Update(UpdateType.REPLACE, ObjectClass.ACCOUNT, attributes, null); syncHelper.AddModUid(createdUids.First(), attributes); - for(int i = 0; i < 10; i++) + for (int i = 0; i < 10; i++) { attributes = GetNormalAttributes_Account(); createUid = CreateAndVerifyObject(connector, ObjectClass.ACCOUNT, @@ -1988,7 +1999,7 @@ public void Init(SyncToken token) public void AddModUid(Uid uid, ICollection attributes) { - _mods[uid]=attributes; + _mods[uid] = attributes; } public void AddDelUid(Uid uid) @@ -2003,29 +2014,48 @@ public bool SyncHandler_Initial(SyncDelta delta) return true; } - public bool SyncHandler_ModifiedAccounts(SyncDelta delta) + public SyncResultsHandler SyncHandler_ModifiedAccounts { - _token = delta.Token; - if(delta.DeltaType.Equals(SyncDeltaType.CREATE_OR_UPDATE)) { - // just ignore extra ones. they might have come in by other means - if (_mods.ContainsKey(delta.Uid)) + get + { + return new SyncResultsHandler() { - ICollection requestedAttrs = _mods[delta.Uid]; - - ActiveDirectoryConnectorTest.VerifyObject(requestedAttrs, - delta.Object); - _mods.Remove(delta.Uid); - } + Handle = delta => + { + _token = delta.Token; + if (delta.DeltaType.Equals(SyncDeltaType.CREATE_OR_UPDATE)) + { + // just ignore extra ones. they might have come in by other means + if (_mods.ContainsKey(delta.Uid)) + { + ICollection requestedAttrs = _mods[delta.Uid]; + + ActiveDirectoryConnectorTest.VerifyObject(requestedAttrs, + delta.Object); + _mods.Remove(delta.Uid); + } + } + return true; + } + }; } - return true; } - public bool SyncHandler_DeletedAccounts(SyncDelta delta) + public SyncResultsHandler SyncHandler_DeletedAccounts { - _token = delta.Token; + get + { + return new SyncResultsHandler() + { + Handle = delta => + { + _token = delta.Token; - _dels.Remove(delta.Uid); - return true; + _dels.Remove(delta.Uid); + return true; + } + }; + } } public bool SyncHandler_Mixed(SyncDelta delta) @@ -2045,7 +2075,7 @@ public void CheckAllSyncsProcessed() } } - public void RunScript(ActiveDirectoryConnector connector, String user, + public void RunScript(ActiveDirectoryConnector connector, String user, string password, string prefix) { string tempFileName = Path.GetTempFileName(); @@ -2053,9 +2083,9 @@ public void RunScript(ActiveDirectoryConnector connector, String user, String arg1Name = "ARG1"; string scriptText = String.Format( - "echo %{0}%:%{1}%:%USERNAME%:%PASSWORD% > \"{2}\"", prefix + arg0Name, + "echo %{0}%:%{1}%:%USERNAME%:%PASSWORD% > \"{2}\"", prefix + arg0Name, prefix + arg1Name, tempFileName); - + IDictionary arguments = new Dictionary(); string arg0 = "argument_zero"; string arg1 = "argument one"; @@ -2087,37 +2117,37 @@ public void RunScript(ActiveDirectoryConnector connector, String user, Assert.AreEqual((arg0), returnedArray[0]); Assert.AreEqual((arg1), returnedArray[1]); } -/* - [Test] - public void testBooScript() - { - //Initialize Connector - ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init(GetConfiguration()); + /* + [Test] + public void testBooScript() + { + //Initialize Connector + ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); + connector.Init(GetConfiguration()); - try - { - string tempFileName = Path.GetTempFileName(); - StringBuilder scriptText = new StringBuilder(); - scriptText.Append("print(\"this is, \");"); - scriptText.Append("print(\"a test.\");"); + try + { + string tempFileName = Path.GetTempFileName(); + StringBuilder scriptText = new StringBuilder(); + scriptText.Append("print(\"this is, \");"); + scriptText.Append("print(\"a test.\");"); - IDictionary arguments = new Dictionary(); - string arg0 = "argument_zero"; - string arg1 = "argument one"; - arguments.Add("ARG0", arg0); - arguments.Add("ARG1", arg1); + IDictionary arguments = new Dictionary(); + string arg0 = "argument_zero"; + string arg1 = "argument one"; + arguments.Add("ARG0", arg0); + arguments.Add("ARG1", arg1); - OperationOptionsBuilder builder = new OperationOptionsBuilder(); + OperationOptionsBuilder builder = new OperationOptionsBuilder(); - ScriptContext context = new ScriptContext("Boo", scriptText.ToString(), arguments); - object resultObject = connector.RunScriptOnResource(context, builder.Build()); - } - finally - { - } - } -*/ + ScriptContext context = new ScriptContext("Boo", scriptText.ToString(), arguments); + object resultObject = connector.RunScriptOnResource(context, builder.Build()); + } + finally + { + } + } + */ // does a create and verify, then looks up and returns // the new user's dn (used for adding to a group) @@ -2160,7 +2190,7 @@ public Uid UpdateReplaceAndVerifyObject(ActiveDirectoryConnector connector, } public Uid UpdateAddAndVerifyUser(ActiveDirectoryConnector connector, - ObjectClass oclass, Uid uid, ICollection attributes, + ObjectClass oclass, Uid uid, ICollection attributes, OperationOptions searchOptions) { // find the existing one, and save off all attributes @@ -2273,7 +2303,7 @@ public void TestOuSearch() ActiveDirectoryConfiguration config = (ActiveDirectoryConfiguration)ConfigHelper.GetConfiguration(); connector.Init(config); ObjectClass OUObjectClass = ActiveDirectoryConnector.ouObjectClass; - + ICollection foundObjects = TestHelpers.SearchToList( connector, OUObjectClass, null); Assert.Greater(foundObjects.Count, 0); @@ -2284,7 +2314,7 @@ public void TestUnmatchedCaseGUIDSearch() { //Initialize Connector ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Uid userUid = null; try { @@ -2321,11 +2351,11 @@ public void TestUnmatchedCaseGUIDSearch() public void TestObjectRename() { var sut = new ActiveDirectoryConnector(); - sut.Init( ConfigHelper.GetConfiguration() ); + sut.Init(ConfigHelper.GetConfiguration()); - RenameObjectAndVerify( sut, ObjectClass.ACCOUNT, GetNormalAttributes_Account() ); - RenameObjectAndVerify( sut, ActiveDirectoryConnector.groupObjectClass, GetNormalAttributes_Group() ); - RenameObjectAndVerify( sut, ActiveDirectoryConnector.ouObjectClass, GetNormalAttributes_OrganizationalUnit() ); + RenameObjectAndVerify(sut, ObjectClass.ACCOUNT, GetNormalAttributes_Account()); + RenameObjectAndVerify(sut, ActiveDirectoryConnector.groupObjectClass, GetNormalAttributes_Group()); + RenameObjectAndVerify(sut, ActiveDirectoryConnector.ouObjectClass, GetNormalAttributes_OrganizationalUnit()); } private void RenameObjectAndVerify(ActiveDirectoryConnector connector, ObjectClass oc, ICollection createAttributes) @@ -2335,43 +2365,43 @@ private void RenameObjectAndVerify(ActiveDirectoryConnector connector, ObjectCla try { // create the objec - createdUid = CreateAndVerifyObject( connector, oc, createAttributes ); + createdUid = CreateAndVerifyObject(connector, oc, createAttributes); // update the name of the object - var oldName = ConnectorAttributeUtil.GetNameFromAttributes( createAttributes ); - var newName = ActiveDirectoryUtils.GetRelativeName( oldName ); - newName = newName.Trim() + "_new, " + GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ); + var oldName = ConnectorAttributeUtil.GetNameFromAttributes(createAttributes); + var newName = ActiveDirectoryUtils.GetRelativeName(oldName); + newName = newName.Trim() + "_new, " + GetProperty(ConfigHelper.CONFIG_PROPERTY_CONTAINER); - updatedUid = UpdateReplaceAndVerifyObject( connector, oc, createdUid, - new List() { ConnectorAttributeBuilder.Build( Name.NAME, newName ) } ); + updatedUid = UpdateReplaceAndVerifyObject(connector, oc, createdUid, + new List() { ConnectorAttributeBuilder.Build(Name.NAME, newName) }); - if (oc.Equals( ObjectClass.ACCOUNT )) + if (oc.Equals(ObjectClass.ACCOUNT)) { - Assert.AreEqual( createdUid, updatedUid, "The Uid of an object of type ACCOUNT must not change." ); + Assert.AreEqual(createdUid, updatedUid, "The Uid of an object of type ACCOUNT must not change."); } // test if the original object exists - var nameFilter = FilterBuilder.EqualTo( ConnectorAttributeBuilder.Build( Name.NAME, oldName.Value ) ); + var nameFilter = FilterBuilder.EqualTo(ConnectorAttributeBuilder.Build(Name.NAME, oldName.Value)); var optionsBuilder = new OperationOptionsBuilder() { AttributesToGet = new[] { Name.NAME } }; - var originalObjects = TestHelpers.SearchToList( connector, oc, nameFilter, optionsBuilder.Build() ); - Assert.AreEqual( 0, originalObjects.Count, - string.Format( System.Globalization.CultureInfo.InvariantCulture, - "An object of type '{0}' with the original name exists.", oc ) ); + var originalObjects = TestHelpers.SearchToList(connector, oc, nameFilter, optionsBuilder.Build()); + Assert.AreEqual(0, originalObjects.Count, + string.Format(System.Globalization.CultureInfo.InvariantCulture, + "An object of type '{0}' with the original name exists.", oc)); } finally { if (createdUid != null) { - DeleteAndVerifyObject( connector, oc, createdUid, false, false ); + DeleteAndVerifyObject(connector, oc, createdUid, false, false); } //make sure that the updated object is deleted as well if (updatedUid != null) { - DeleteAndVerifyObject( connector, oc, updatedUid, false, false ); + DeleteAndVerifyObject(connector, oc, updatedUid, false, false); } } } @@ -2397,7 +2427,7 @@ public Uid CreateObject(ActiveDirectoryConnector connector, Assert.AreEqual(1, foundObjects.Count); DeleteAndVerifyObject(connector, oclass, foundObjects.ElementAt(0).Uid, false, true); } - + // create object Uid uid = connector.Create(oclass, attributes, null); Assert.IsNotNull(uid); @@ -2429,7 +2459,7 @@ public ICollection GetNormalAttributes_Account() // the container ... is a fabricated attribute attributes.Add(ConnectorAttributeBuilder.Build( - "ad_container", GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ) ) ); + "ad_container", GetProperty(ConfigHelper.CONFIG_PROPERTY_CONTAINER))); attributes.Add(ConnectorAttributeBuilder.Build( "userPassword", "secret")); attributes.Add(ConnectorAttributeBuilder.Build( @@ -2442,7 +2472,7 @@ public ICollection GetNormalAttributes_Account() "displayName", "nunit test user " + randomNumber)); attributes.Add(ConnectorAttributeBuilder.Build( Name.NAME, "cn=nunit" + randomNumber + "," + - GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ) ) ); + GetProperty(ConfigHelper.CONFIG_PROPERTY_CONTAINER))); attributes.Add(ConnectorAttributeBuilder.Build( "mail", "nunitUser" + randomNumber + "@some.com")); attributes.Add(ConnectorAttributeBuilder.Build( @@ -2457,7 +2487,7 @@ public ICollection GetAllAttributes_Account() // the container ... is a fabricated attribute attributes.Add(ConnectorAttributeBuilder.Build( - "ad_container", GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ) ) ); + "ad_container", GetProperty(ConfigHelper.CONFIG_PROPERTY_CONTAINER))); GuardedString password = new GuardedString(); foreach (char c in "secret") { @@ -2614,7 +2644,7 @@ public ICollection GetAllAttributes_Account() // now set name operational attribute attributes.Add(ConnectorAttributeBuilder.Build( Name.NAME, "cn=nunit" + randomNumber + "," + - GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ) ) ); + GetProperty(ConfigHelper.CONFIG_PROPERTY_CONTAINER))); /* @@ -2639,7 +2669,7 @@ public ICollection GetNormalAttributes_Group() "description", "Original Description" + randomNumber)); attributes.Add(ConnectorAttributeBuilder.Build( Name.NAME, "cn=nunitGroup" + randomNumber + "," + - GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ) ) ); + GetProperty(ConfigHelper.CONFIG_PROPERTY_CONTAINER))); attributes.Add(ConnectorAttributeBuilder.Build( "groupType", 4)); return attributes; @@ -2652,7 +2682,7 @@ public ICollection GetNormalAttributes_OrganizationalUnit() attributes.Add(ConnectorAttributeBuilder.Build( Name.NAME, "ou=nunitOU" + randomNumber + "," + - GetProperty( ConfigHelper.CONFIG_PROPERTY_CONTAINER ) ) ); + GetProperty(ConfigHelper.CONFIG_PROPERTY_CONTAINER))); return attributes; } @@ -2667,7 +2697,7 @@ private static void VerifyObject(ICollection requestedAttrib String uidValue = uid.GetUidValue(); Assert.That(uidValue.StartsWith((""), "GUID for account objects must end with >"); - Assert.That(uidValue.ToLower().Replace("guid", "GUID").Equals(uidValue), + Assert.That(uidValue.ToLower().Replace("guid", "GUID").Equals(uidValue), "GUID for account objects must have lowercase hex strings"); } @@ -2792,7 +2822,7 @@ public ConnectorObject GetConnectorObjectFromUid( } public ConnectorObject GetConnectorObjectFromUid( - ActiveDirectoryConnector connector, ObjectClass oclass, Uid uid, + ActiveDirectoryConnector connector, ObjectClass oclass, Uid uid, OperationOptions options) { // get sid to check permissions @@ -2808,7 +2838,7 @@ public ICollection GetDefaultAttributesToGet(ObjectClass oclass) ICollection attributesToGet = new HashSet(); ActiveDirectoryConnector connector = new ActiveDirectoryConnector(); - connector.Init( ConfigHelper.GetConfiguration() ); + connector.Init(ConfigHelper.GetConfiguration()); Schema schema = connector.Schema(); ObjectClassInfo ocInfo = schema.FindObjectClassInfo(oclass.GetObjectClassValue()); Assert.IsNotNull(ocInfo); @@ -2837,20 +2867,22 @@ public GuardedString GetGuardedString(string regularString) int GetRandomNumber() { const int randomRange = 10000000; - + int number = 0; // having trouble with duplicate random numbers, so try a few hundred // times to get a unique one before giving up. - for(int i=0;i<500;i++) { + for (int i = 0; i < 500; i++) + { number = _rand.Next(randomRange); #if DEBUG - // make sure the debug numbers are in a different - // range than release ones to eliminate conflicts during - // the build where both configurations are run concurrently - number += randomRange; + // make sure the debug numbers are in a different + // range than release ones to eliminate conflicts during + // the build where both configurations are run concurrently + number += randomRange; #endif - if(!(randomList.Contains(number))) { + if (!(randomList.Contains(number))) + { randomList.Add(number); break; } diff --git a/ActiveDirectoryConnectorTests/ConfigHelper.cs b/ActiveDirectoryConnectorTests/ConfigHelper.cs index 4202a95..50d1804 100644 --- a/ActiveDirectoryConnectorTests/ConfigHelper.cs +++ b/ActiveDirectoryConnectorTests/ConfigHelper.cs @@ -20,10 +20,7 @@ * "Portions Copyrighted [year] [name of copyright owner]" * ==================== */ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using Org.IdentityConnectors.Framework.Spi; using Org.IdentityConnectors.Test.Common; diff --git a/ActiveDirectoryConnectorTests/version.template b/ActiveDirectoryConnectorTests/version.template index bd2666a..77d55b2 100644 --- a/ActiveDirectoryConnectorTests/version.template +++ b/ActiveDirectoryConnectorTests/version.template @@ -1 +1 @@ -1.0.0.0 \ No newline at end of file +1.4.0.0 \ No newline at end of file diff --git a/ExchangeConnector/ExchangeConnector.cs b/ExchangeConnector/ExchangeConnector.cs index a509b69..45f423f 100644 --- a/ExchangeConnector/ExchangeConnector.cs +++ b/ExchangeConnector/ExchangeConnector.cs @@ -19,13 +19,13 @@ // enclosed by brackets [] replaced by your own identifying information: // "Portions Copyrighted [year] [name of copyright owner]" // ==================== +// Portions Copyrighted 2014 ForgeRock AS. // // Tomas Knappek namespace Org.IdentityConnectors.Exchange { using System; - using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; @@ -79,7 +79,7 @@ public class ExchangeConnector : ActiveDirectoryConnector /// Database attribute name as in AD /// internal const string AttDatabaseADName = "homeMDB"; - + /// /// Attribute mapping constant /// @@ -308,7 +308,7 @@ public override Uid Update( if (rcptType == RcptTypeMailUser) { if (type == UpdateType.REPLACE) - { + { if (origRcptType != rcptType) { Command cmdEnable = ExchangeUtility.GetCommand( @@ -397,7 +397,7 @@ public override void Test() public override void Sync( ObjectClass objClass, SyncToken token, SyncResultsHandler handler, OperationOptions options) { - ExchangeUtility.NullCheck(objClass, "oclass", this.configuration); + ExchangeUtility.NullCheck(objClass, "oclass", this.configuration); // we handle accounts only if (!objClass.Is(ObjectClass.ACCOUNT_NAME)) @@ -405,7 +405,7 @@ public override void Sync( base.Sync(objClass, token, handler, options); return; } - + ICollection attsToGet = null; if (options != null && options.AttributesToGet != null) { @@ -413,30 +413,33 @@ public override void Sync( } // delegate to get the exchange attributes if requested - SyncResultsHandler xchangeHandler = delegate(SyncDelta delta) + SyncResultsHandler xchangeHandler = new SyncResultsHandler() { - if (delta.DeltaType == SyncDeltaType.DELETE) + Handle = delta => { - return handler(delta); - } + if (delta.DeltaType == SyncDeltaType.DELETE) + { + return handler.Handle(delta); + } - // replace the ad attributes with exchange one and add recipient type - ConnectorObject updated = ExchangeUtility.ReplaceAttributes(delta.Object, attsToGet, AttMapFromAD); - updated = this.AddExchangeAttributes(objClass, updated, attsToGet); - if (updated != delta.Object) - { - // build new sync delta, cause we changed the object - SyncDeltaBuilder deltaBuilder = new SyncDeltaBuilder - { + // replace the ad attributes with exchange one and add recipient type + ConnectorObject updated = ExchangeUtility.ReplaceAttributes(delta.Object, attsToGet, AttMapFromAD); + updated = this.AddExchangeAttributes(objClass, updated, attsToGet); + if (updated != delta.Object) + { + // build new sync delta, cause we changed the object + SyncDeltaBuilder deltaBuilder = new SyncDeltaBuilder + { DeltaType = delta.DeltaType, Token = delta.Token, Uid = delta.Uid, Object = updated - }; - delta = deltaBuilder.Build(); - } + }; + delta = deltaBuilder.Build(); + } - return handler(delta); + return handler.Handle(delta); + } }; // call AD sync, use xchangeHandler @@ -453,7 +456,7 @@ public override void Sync( public override void ExecuteQuery( ObjectClass oclass, string query, ResultsHandler handler, OperationOptions options) { - ExchangeUtility.NullCheck(oclass, "oclass", this.configuration); + ExchangeUtility.NullCheck(oclass, "oclass", this.configuration); // we handle accounts only if (!oclass.Is(ObjectClass.ACCOUNT_NAME)) @@ -469,13 +472,16 @@ public override void ExecuteQuery( } // delegate to get the exchange attributes if requested - ResultsHandler filter = delegate(ConnectorObject cobject) - { - ConnectorObject filtered = ExchangeUtility.ReplaceAttributes( - cobject, attsToGet, AttMapFromAD); - filtered = this.AddExchangeAttributes(oclass, filtered, attsToGet); - return handler(filtered); - }; + ResultsHandler filter = new ResultsHandler() + { + Handle = cobject => + { + ConnectorObject filtered = ExchangeUtility.ReplaceAttributes( + cobject, attsToGet, AttMapFromAD); + filtered = this.AddExchangeAttributes(oclass, filtered, attsToGet); + return handler.Handle(filtered); + } + }; ResultsHandler handler2use = handler; OperationOptions options2use = options; @@ -521,7 +527,7 @@ public override FilterTranslator CreateFilterTranslator(ObjectClass ocla public override void Init(Configuration configuration) { this.configuration = (ExchangeConfiguration)configuration; - base.Init(configuration); + base.Init(configuration); this.runspace = new RunSpaceInstance(RunSpaceInstance.SnapIn.Exchange, configuration.ConnectorMessages); } @@ -541,7 +547,7 @@ public sealed override void Dispose() /// Attribute to be normalized /// Normalized attribute public ConnectorAttribute NormalizeAttribute(ObjectClass oclass, ConnectorAttribute attribute) - //public override ConnectorAttribute NormalizeAttribute(ObjectClass oclass, ConnectorAttribute attribute) + //public override ConnectorAttribute NormalizeAttribute(ObjectClass oclass, ConnectorAttribute attribute) { // normalize the attribute using AD connector first //attribute = base.NormalizeAttribute(oclass, attribute); @@ -699,7 +705,7 @@ private static T GetFirstElement(IEnumerable collection) where T : class /// In case of some troubles in powershell (if the /// user is not found we get this exception too) private ConnectorObject AddExchangeAttributes(ObjectClass oc, ConnectorObject cobject, IEnumerable attToGet) - { + { ExchangeUtility.NullCheck(oc, "name", this.configuration); ExchangeUtility.NullCheck(oc, "cobject", this.configuration); @@ -736,7 +742,7 @@ private ConnectorObject AddExchangeAttributes(ObjectClass oc, ConnectorObject co cobjBuilder.AddAttributes(cobject.GetAttributes()); PSExchangeConnector.CommandInfo cmdInfo = PSExchangeConnector.CommandInfo.GetUser; - + // prepare the connector attribute list to get the command ICollection attributes = new Collection { cobject.Name }; @@ -749,19 +755,19 @@ private ConnectorObject AddExchangeAttributes(ObjectClass oc, ConnectorObject co user = GetFirstElement(foundObjects); foreach (var info in user.Properties) { - ConnectorAttribute att = GetAsAttribute(info); + ConnectorAttribute att = GetAsAttribute(info); if (att != null && lattToGet.Contains(att.Name)) { cobjBuilder.AddAttribute(att); lattToGet.Remove(att.Name); - } + } } if (lattToGet.Count == 0) { return cobjBuilder.Build(); } - } + } if (user == null) { @@ -794,10 +800,10 @@ private ConnectorObject AddExchangeAttributes(ObjectClass oc, ConnectorObject co lattToGet.Remove(att.Name); } } - } + } return cobjBuilder.Build(); - } + } /// /// Invokes command in PowerShell runspace, this method is just helper @@ -823,7 +829,7 @@ private ICollection InvokePipeline(Command cmd) { throw new ConnectorException(this.configuration.ConnectorMessages.Format( "ex_powershell_problem", "Problem while PowerShell execution {0}", e)); - } + } } /// @@ -849,11 +855,14 @@ private ConnectorObject ADSearchByUid(Uid uid, ObjectClass oclass, OperationOpti if (queries.Count == 1) { - ResultsHandler handler = delegate(ConnectorObject cobject) - { - ret = cobject; - return false; - }; + ResultsHandler handler = new ResultsHandler() + { + Handle = cobject => + { + ret = cobject; + return false; + } + }; base.ExecuteQuery(oclass, queries[0], handler, options); } @@ -885,7 +894,7 @@ private PSObject GetUser(PSExchangeConnector.CommandInfo cmdInfo, ICollection /// Filter translator which does MS Exchange specific translation diff --git a/ExchangeConnector/RunSpaceInstance.cs b/ExchangeConnector/RunSpaceInstance.cs index ec0b110..1ebfb4f 100644 --- a/ExchangeConnector/RunSpaceInstance.cs +++ b/ExchangeConnector/RunSpaceInstance.cs @@ -33,8 +33,6 @@ namespace Org.IdentityConnectors.Exchange using System.Management.Automation; using System.Management.Automation.Runspaces; using System.Text; - using System.Linq; - using Org.IdentityConnectors.Framework.Common.Exceptions; using Org.IdentityConnectors.Framework.Common.Objects; using Org.IdentityConnectors.Common; diff --git a/ExchangeConnector/version.template b/ExchangeConnector/version.template index bd2666a..77d55b2 100644 --- a/ExchangeConnector/version.template +++ b/ExchangeConnector/version.template @@ -1 +1 @@ -1.0.0.0 \ No newline at end of file +1.4.0.0 \ No newline at end of file From 765122cf619da807086723122ee4e9737752e37b Mon Sep 17 00:00:00 2001 From: Chris Drake Date: Thu, 17 Apr 2014 13:12:07 +0000 Subject: [PATCH 23/33] OPENICF-215 Spaces removed from DN during normalization if preceded by an escaped comma --- ActiveDirectoryConnector/ActiveDirectoryUtils.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ActiveDirectoryConnector/ActiveDirectoryUtils.cs b/ActiveDirectoryConnector/ActiveDirectoryUtils.cs index 8d85d66..d5a7128 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryUtils.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryUtils.cs @@ -34,6 +34,7 @@ using Org.IdentityConnectors.Common.Security; using System.DirectoryServices.ActiveDirectory; using System.Runtime.InteropServices; +using System.Text.RegularExpressions; namespace Org.IdentityConnectors.ActiveDirectory { @@ -539,8 +540,13 @@ internal String GetADObjectClass(ObjectClass oclass) /// public static String NormalizeLdapString(String ldapString) { + /// (? Date: Thu, 1 May 2014 08:36:07 +0000 Subject: [PATCH 24/33] Fix failing build job because of compilation error --- ActiveDirectoryConnector/ActiveDirectoryUtils.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/ActiveDirectoryConnector/ActiveDirectoryUtils.cs b/ActiveDirectoryConnector/ActiveDirectoryUtils.cs index d5a7128..0bb9826 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryUtils.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryUtils.cs @@ -22,6 +22,7 @@ * Portions Copyrighted 2012-2014 ForgeRock AS. */ using System; +using System.Linq; using System.Collections.Generic; using System.Text; using Org.IdentityConnectors.Framework.Common.Objects; From 328982c23409ce92bc1ef827a4a70b7a0feca69a Mon Sep 17 00:00:00 2001 From: Gael Allioux Date: Thu, 12 Jun 2014 13:26:29 +0000 Subject: [PATCH 25/33] CR-3758 OPENICF-182 AD connector does not work with ICF 1.4 --- .../PasswordChangeHandler.cs | 55 ++++++++++--------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/ActiveDirectoryConnector/PasswordChangeHandler.cs b/ActiveDirectoryConnector/PasswordChangeHandler.cs index 580b0a3..970e374 100644 --- a/ActiveDirectoryConnector/PasswordChangeHandler.cs +++ b/ActiveDirectoryConnector/PasswordChangeHandler.cs @@ -193,31 +193,32 @@ internal PasswordChangeHandler(ActiveDirectoryConfiguration configuration) /// sets the _currentPassword variable /// /// - internal void setCurrentPassword(UnmanagedArray clearChars) - { - _currentPassword = ""; - - // build up the string from the unmanaged array - for (int i = 0; i < clearChars.Length; i++) - { - _currentPassword += clearChars[i]; - } - } + //internal void setCurrentPassword(UnmanagedArray clearChars) + //{ + // _currentPassword = ""; + // // build up the string from the unmanaged array + // for (int i = 0; i < clearChars.Length; i++) + // { + // _currentPassword += clearChars[i]; + // } + //} + // Gael 1.1 legacy /// /// Sets the _newPassword variable /// /// - internal void setNewPassword(UnmanagedArray clearChars) - { - _newPassword = ""; + //internal void setNewPassword(UnmanagedArray clearChars) + //{ + // _newPassword = ""; - // build up the string from the unmanaged array - for (int i = 0; i < clearChars.Length; i++) - { - _newPassword += clearChars[i]; - } - } + // // build up the string from the unmanaged array + // for (int i = 0; i < clearChars.Length; i++) + // { + // _newPassword += clearChars[i]; + // } + //} + // Gael - 1.1 legacy /// /// Does an administrative password change. The Directory @@ -230,8 +231,8 @@ internal void changePassword(DirectoryEntry directoryEntry, GuardedString gsNewPassword) { // decrypt and save the new password - gsNewPassword.Access(setNewPassword); - + _newPassword = SecurityUtil.Decrypt(gsNewPassword); + // get the native com object as an IADsUser, and set the // password IADsUser user = (IADsUser)directoryEntry.NativeObject; @@ -249,9 +250,9 @@ internal void changePassword(DirectoryEntry directoryEntry, GuardedString gsCurrentPassword, GuardedString gsNewPassword) { // decrypt and save the old nad new passwords - gsNewPassword.Access(setNewPassword); - gsCurrentPassword.Access(setCurrentPassword); - + _newPassword = SecurityUtil.Decrypt(gsNewPassword); + _currentPassword = SecurityUtil.Decrypt(gsCurrentPassword); + // get the native com object as an IADsUser, and change the // password IADsUser user = (IADsUser)directoryEntry.NativeObject; @@ -261,18 +262,18 @@ internal void changePassword(DirectoryEntry directoryEntry, /// /// Authenticates the user /// - /// /// /// + /// internal Uid Authenticate(/*DirectoryEntry directoryEntry,*/ string username, - Org.IdentityConnectors.Common.Security.GuardedString password, bool returnUidOnly) + GuardedString password, bool returnUidOnly) { AuthenticationHelper authHelper = new AuthenticationHelper(_configuration); if(returnUidOnly) { return authHelper.GetUidFromSamAccountName(username); } - password.Access(setCurrentPassword); + _currentPassword = SecurityUtil.Decrypt(password); return authHelper.ValidateUserCredentials(username, _currentPassword); } From 9f5eadc7faa13298e20c9da84858417a202ed0f6 Mon Sep 17 00:00:00 2001 From: Gael Allioux Date: Thu, 12 Jun 2014 13:47:08 +0000 Subject: [PATCH 26/33] CR-3479 OPENICF-225 NOT operator --- .../ActiveDirectoryFilterTranslator.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ActiveDirectoryConnector/ActiveDirectoryFilterTranslator.cs b/ActiveDirectoryConnector/ActiveDirectoryFilterTranslator.cs index 8bca95f..a8a3ada 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryFilterTranslator.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryFilterTranslator.cs @@ -64,7 +64,7 @@ protected override String CreateContainsExpression(ContainsFilter filter, StringBuilder builder = new StringBuilder(); if (not) { - builder.Append("!("); + builder.Append("(!"); } if (attrNames.Length == 1) { builder.Append('('); @@ -108,7 +108,7 @@ protected override String CreateStartsWithExpression(StartsWithFilter filter, StringBuilder builder = new StringBuilder(); if (not) { - builder.Append("!("); + builder.Append("(!"); } if (attrNames.Length == 1) { builder.Append('('); @@ -142,7 +142,7 @@ protected override String CreateEndsWithExpression(EndsWithFilter filter, StringBuilder builder = new StringBuilder(); if (not) { - builder.Append("!("); + builder.Append("(!"); } if (attrNames.Length == 1) { builder.Append('('); @@ -247,7 +247,7 @@ protected override String CreateGreaterThanOrEqualExpression( StringBuilder builder = new StringBuilder(); if (not) { - builder.Append("!("); + builder.Append("(!"); } BuildGreaterOrEqualFilter(builder, attrNames, filter.GetValue()); if (not) { @@ -283,7 +283,7 @@ protected override String CreateLessThanOrEqualExpression( StringBuilder builder = new StringBuilder(); if (not) { - builder.Append("!("); + builder.Append("(!"); } BuildLessOrEqualFilter(builder, attrNames, filter.GetValue()); if (not) { From 4f8370e23cddf4cad183bb0af060946c41aa4823 Mon Sep 17 00:00:00 2001 From: Laszlo Hordos Date: Fri, 20 Jun 2014 13:29:25 +0000 Subject: [PATCH 27/33] =?UTF-8?q?CR-3827=20/=20OPENICF-243=20=E2=80=93=20T?= =?UTF-8?q?here=20is=20typo=20problem=20in=20the=20methods=20name=20CR-382?= =?UTF-8?q?6=20/=20OPENICF-200,=20OPENICF-160=20(=20OPENICF-207=20)=20-=20?= =?UTF-8?q?Documentation=20of=20.Net=20Connectors=20CR-3800=20/=20OPENICF-?= =?UTF-8?q?237=20=E2=80=93=20Add=20more=20logging=20to=20.Net=20ConnectorS?= =?UTF-8?q?erver=20FR-228=20/=20OPENICF241=20-=20Update=20the=20legal=20fi?= =?UTF-8?q?les=20in=20OpenICF=20binaries?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ActiveDirectoryConnector/Messages.resx | 5 ++++- DotNetCommonBuild.Targets | 22 ++++++++++++---------- ExchangeConnector/Messages.resx | 3 +++ 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/ActiveDirectoryConnector/Messages.resx b/ActiveDirectoryConnector/Messages.resx index ab15935..947472a 100644 --- a/ActiveDirectoryConnector/Messages.resx +++ b/ActiveDirectoryConnector/Messages.resx @@ -1,4 +1,4 @@ - + @@ -32,20 +32,21 @@ - + + - - - - - + + + + + - + @@ -94,12 +95,13 @@ - + + diff --git a/ExchangeConnector/Messages.resx b/ExchangeConnector/Messages.resx index 01b7573..a2d6205 100644 --- a/ExchangeConnector/Messages.resx +++ b/ExchangeConnector/Messages.resx @@ -306,4 +306,7 @@ There is no supported Exchange PowerShell snap-in registered. + + User + \ No newline at end of file From 2a544e53657901eff2f59835486a76b115b8dca8 Mon Sep 17 00:00:00 2001 From: Laszlo Hordos Date: Thu, 26 Jun 2014 10:01:40 +0000 Subject: [PATCH 28/33] Update the project version after release --- ActiveDirectoryConnector/version.template | 2 +- ActiveDirectoryConnectorTests/version.template | 2 +- ExchangeConnector/version.template | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ActiveDirectoryConnector/version.template b/ActiveDirectoryConnector/version.template index 77d55b2..34c3267 100644 --- a/ActiveDirectoryConnector/version.template +++ b/ActiveDirectoryConnector/version.template @@ -1 +1 @@ -1.4.0.0 \ No newline at end of file +1.4.1.0 \ No newline at end of file diff --git a/ActiveDirectoryConnectorTests/version.template b/ActiveDirectoryConnectorTests/version.template index 77d55b2..34c3267 100644 --- a/ActiveDirectoryConnectorTests/version.template +++ b/ActiveDirectoryConnectorTests/version.template @@ -1 +1 @@ -1.4.0.0 \ No newline at end of file +1.4.1.0 \ No newline at end of file diff --git a/ExchangeConnector/version.template b/ExchangeConnector/version.template index 77d55b2..34c3267 100644 --- a/ExchangeConnector/version.template +++ b/ExchangeConnector/version.template @@ -1 +1 @@ -1.4.0.0 \ No newline at end of file +1.4.1.0 \ No newline at end of file From d8e34ae8afbcd492bee9cc2d9f0c569110d8d6b5 Mon Sep 17 00:00:00 2001 From: Gael Allioux Date: Fri, 18 Jul 2014 08:56:43 +0000 Subject: [PATCH 29/33] CR-4033 OPENICF-262 --- ActiveDirectoryConnector/ActiveDirectoryConnector.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs b/ActiveDirectoryConnector/ActiveDirectoryConnector.cs index 0d7ffec..1666806 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryConnector.cs @@ -179,10 +179,14 @@ public virtual Uid Create(ObjectClass oclass, if ((ObjectClass.ACCOUNT.Equals(oclass)) && (ConnectorAttributeUtil.Find(OperationalAttributes.ENABLE_NAME, attributes) == null)) { - attributes.Add(ConnectorAttributeBuilder.Build(OperationalAttributes.ENABLE_NAME, true)); + ICollection temp = new HashSet(attributes); + temp.Add(ConnectorAttributeBuilder.Build(OperationalAttributes.ENABLE_NAME, true)); + _utils.UpdateADObject(oclass, newDe, temp, UpdateType.REPLACE, _configuration); + } + else + { + _utils.UpdateADObject(oclass, newDe, attributes, UpdateType.REPLACE, _configuration); } - _utils.UpdateADObject(oclass, newDe, attributes, - UpdateType.REPLACE, _configuration); Object guidValue = newDe.Properties["objectGUID"].Value; if (guidValue != null) { From 73fc17a281881aa896197d377a165f7e353b8f29 Mon Sep 17 00:00:00 2001 From: Laszlo Hordos Date: Wed, 30 Jul 2014 09:42:37 +0000 Subject: [PATCH 30/33] CR-4094 / OPENICF-269 - Add the 'legal-notices' folder with necessary license files --- DotNetCommonBuild.Targets | 12 +- THIRDPARTYREADME.txt | 3591 --------------------------- legal-notices/CDDLv1_0.txt | 384 +++ legal-notices/ForgeRock_License.txt | 144 ++ license.txt | 383 --- 5 files changed, 536 insertions(+), 3978 deletions(-) delete mode 100644 THIRDPARTYREADME.txt create mode 100644 legal-notices/CDDLv1_0.txt create mode 100644 legal-notices/ForgeRock_License.txt delete mode 100644 license.txt diff --git a/DotNetCommonBuild.Targets b/DotNetCommonBuild.Targets index 59d4e5c..e1b6f92 100644 --- a/DotNetCommonBuild.Targets +++ b/DotNetCommonBuild.Targets @@ -29,6 +29,7 @@ ForgeRock AS Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved. $(MSBuildProjectDirectory)\..\Build + false @@ -61,17 +62,20 @@ - - + + + - + + + + ZipFileName="$(CommonBuildDir)\$(AssemblyName)-$(Major).$(Minor).$(Build).$(Revision)-SNAPSHOT.zip" Condition=" '$(Configuration)'!='Release' "/> diff --git a/THIRDPARTYREADME.txt b/THIRDPARTYREADME.txt deleted file mode 100644 index 797aa12..0000000 --- a/THIRDPARTYREADME.txt +++ /dev/null @@ -1,3591 +0,0 @@ -DO NOT TRANSLATE OR LOCALIZE -*************************************************************************** -%%The following software may be included in this product: -Groovy Scripting Language -Use of any of this software is governed by the terms of the license below: -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -"submitted" means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this -License, each Contributor hereby grants to You a perpetual, worldwide, -non-exclusive, no-charge, royalty-free, irrevocable copyright license to -reproduce, prepare Derivative Works of, publicly display, publicly perform, -sublicense, and distribute the Work and such Derivative Works in Source or -Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, -each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) patent -license to make, have made, use, offer to sell, sell, import, and otherwise -transfer the Work, where such license applies only to those patent claims -licensable by such Contributor that are necessarily infringed by their -Contribution(s) alone or by combination of their Contribution(s) with the Work -to which such Contribution(s) was submitted. If You institute patent litigation -against any entity (including a cross-claim or counterclaim in a lawsuit) -alleging that the Work or a Contribution incorporated within the Work -constitutes direct or contributory patent infringement, then any patent licenses -granted to You under this License for that Work shall terminate as of the date -such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or -Derivative Works thereof in any medium, with or without modifications, and in -Source or Object form, provided that You meet the following conditions: - -1. You must give any other recipients of the Work or Derivative Works a copy -of this License; and - -2. You must cause any modified files to carry prominent notices stating that -You changed the files; and - -3. You must retain, in the Source form of any Derivative Works that You -distribute, all copyright, patent, trademark, and attribution notices from the -Source form of the Work, excluding those notices that do not pertain to any part -of the Derivative Works; and - -4. If the Work includes a "NOTICE" text file as part of its distribution, -then any Derivative Works that You distribute must include a readable copy of -the attribution notices contained within such NOTICE file, excluding those -notices that do not pertain to any part of the Derivative Works, in at least one -of the following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. - -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -provided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any -Contribution intentionally submitted for inclusion in the Work by You to the -Licensor shall be under the terms and conditions of this License, without any -additional terms or conditions. Notwithstanding the above, nothing herein shall -supersede or modify the terms of any separate license agreement you may have -executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, -trademarks, service marks, or product names of the Licensor, except as required -for reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in -writing, Licensor provides the Work (and each Contributor provides its -Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied, including, without limitation, any warranties -or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -PARTICULAR PURPOSE. You are solely responsible for determining the -appropriateness of using or redistributing the Work and assume any risks -associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in -tort (including negligence), contract, or otherwise, unless required by -applicable law (such as deliberate and grossly negligent acts) or agreed to in -writing, shall any Contributor be liable to You for damages, including any -direct, indirect, special, incidental, or consequential damages of any character -arising as a result of this License or out of the use or inability to use the -Work (including but not limited to damages for loss of goodwill, work stoppage, -computer failure or malfunction, or any and all other commercial damages or -losses), even if such Contributor has been advised of the possibility of such -damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or -Derivative Works thereof, You may choose to offer, and charge a fee for, -acceptance of support, warranty, indemnity, or other liability obligations -and/or rights consistent with this License. However, in accepting such -obligations, You may act only on Your own behalf and on Your sole -responsibility, not on behalf of any other Contributor, and only if You agree to -indemnify, defend, and hold each Contributor harmless for any liability incurred -by, or claims asserted against, such Contributor by reason of your accepting any -such warranty or additional liability. - -END OF TERMS AND CONDITIONS -APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same "printed page" as the copyright notice for easier identification within -third-party archives. -Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, -Version 2.0 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or -agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -or implied. See the License for the specific language governing permissions and -limitations under the License. -*************************************************************************** -%%The following software may be included in this product: -Apache Commons Pool -Use of any of this software is governed by the terms of the license below: -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, -and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by -the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all -other entities that control, are controlled by, or are under common -control with that entity. For the purposes of this definition, -"control" means (i) the power, direct or indirect, to cause the -direction or management of such entity, whether by contract or -otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity -exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, -including but not limited to software source code, documentation -source, and configuration files. - -"Object" form shall mean any form resulting from mechanical -transformation or translation of a Source form, including but -not limited to compiled object code, generated documentation, -and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or -Object form, made available under the License, as indicated by a -copyright notice that is included in or attached to the work -(an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object -form, that is based on (or derived from) the Work and for which the -editorial revisions, annotations, elaborations, or other modifications -represent, as a whole, an original work of authorship. For the purposes -of this License, Derivative Works shall not include works that remain -separable from, or merely link (or bind by name) to the interfaces of, -the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including -the original version of the Work and any modifications or additions -to that Work or Derivative Works thereof, that is intentionally -submitted to Licensor for inclusion in the Work by the copyright owner -or by an individual or Legal Entity authorized to submit on behalf of -the copyright owner. For the purposes of this definition, "submitted" -means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, -and issue tracking systems that are managed by, or on behalf of, the -Licensor for the purpose of discussing and improving the Work, but -excluding communication that is conspicuously marked or otherwise -designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity -on behalf of whom a Contribution has been received by Licensor and -subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the -Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -(except as stated in this section) patent license to make, have made, -use, offer to sell, sell, import, and otherwise transfer the Work, -where such license applies only to those patent claims licensable -by such Contributor that are necessarily infringed by their -Contribution(s) alone or by combination of their Contribution(s) -with the Work to which such Contribution(s) was submitted. If You -institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work -or a Contribution incorporated within the Work constitutes direct -or contributory patent infringement, then any patent licenses -granted to You under this License for that Work shall terminate -as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the -Work or Derivative Works thereof in any medium, with or without -modifications, and in Source or Object form, provided that You -meet the following conditions: - -(a) You must give any other recipients of the Work or -Derivative Works a copy of this License; and - -(b) You must cause any modified files to carry prominent notices -stating that You changed the files; and - -(c) You must retain, in the Source form of any Derivative Works -that You distribute, all copyright, patent, trademark, and -attribution notices from the Source form of the Work, -excluding those notices that do not pertain to any part of -the Derivative Works; and - -(d) If the Work includes a "NOTICE" text file as part of its -distribution, then any Derivative Works that You distribute must -include a readable copy of the attribution notices contained -within such NOTICE file, excluding those notices that do not -pertain to any part of the Derivative Works, in at least one -of the following places: within a NOTICE text file distributed -as part of the Derivative Works; within the Source form or -documentation, if provided along with the Derivative Works; or, -within a display generated by the Derivative Works, if and -wherever such third-party notices normally appear. The contents -of the NOTICE file are for informational purposes only and -do not modify the License. You may add Your own attribution -notices within Derivative Works that You distribute, alongside -or as an addendum to the NOTICE text from the Work, provided -that such additional attribution notices cannot be construed -as modifying the License. - -You may add Your own copyright statement to Your modifications and -may provide additional or different license terms and conditions -for use, reproduction, or distribution of Your modifications, or -for any such Derivative Works as a whole, provided Your use, -reproduction, and distribution of the Work otherwise complies with -the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, -any Contribution intentionally submitted for inclusion in the Work -by You to the Licensor shall be under the terms and conditions of -this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify -the terms of any separate license agreement you may have executed -with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade -names, trademarks, service marks, or product names of the Licensor, -except as required for reasonable and customary use in describing the -origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or -agreed to in writing, Licensor provides the Work (and each -Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied, including, without limitation, any warranties or conditions -of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -PARTICULAR PURPOSE. You are solely responsible for determining the -appropriateness of using or redistributing the Work and assume any -risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, -whether in tort (including negligence), contract, or otherwise, -unless required by applicable law (such as deliberate and grossly -negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, -incidental, or consequential damages of any character arising as a -result of this License or out of the use or inability to use the -Work (including but not limited to damages for loss of goodwill, -work stoppage, computer failure or malfunction, or any and all -other commercial damages or losses), even if such Contributor -has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing -the Work or Derivative Works thereof, You may choose to offer, -and charge a fee for, acceptance of support, warranty, indemnity, -or other liability obligations and/or rights consistent with this -License. However, in accepting such obligations, You may act only -on Your own behalf and on Your sole responsibility, not on behalf -of any other Contributor, and only if You agree to indemnify, -defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason -of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following -boilerplate notice, with the fields enclosed by brackets "[]" -replaced with your own identifying information. (Don't include -the brackets!) The text should be enclosed in the appropriate -comment syntax for the file format. We also recommend that a -file or class name and description of purpose be included on the -same "printed page" as the copyright notice for easier -identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*************************************************************************** -%%The following software may be included in this product: -HSQL Database Engine -Use of any of this software is governed by the terms of the license below: -COPYRIGHTS AND LICENSES - -ORIGINAL LICENSE (a.k.a. "hypersonic_lic.txt") - -For content, code, and products originally developed by Thomas Mueller and the -Hypersonic SQL Group: - -Copyright (c) 1995-2000 by the Hypersonic SQL Group. -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 Hypersonic SQL Group 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE HYPERSONIC SQL GROUP, -OR CONTRIBUTORS 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. - -This software consists of voluntary contributions made by many individuals on -behalf of the -Hypersonic SQL Group. - - - -For work added by the HSQL Development Group (a.k.a. hsqldb_lic.txt): -Copyright (c) 2001-2005, The HSQL Development Group -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 HSQL Development Group 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 HSQL DEVELOPMENT GROUP, HSQLDB.ORG, -OR CONTRIBUTORS 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. -*************************************************************************** -%%The following software may be included in this product: -Derby -Use of any of this software is governed by the terms of the license below: -Apache License, Version 2.0 - -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -"submitted" means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this -License, each Contributor hereby grants to You a perpetual, worldwide, -non-exclusive, no-charge, royalty-free, irrevocable copyright license to -reproduce, prepare Derivative Works of, publicly display, publicly perform, -sublicense, and distribute the Work and such Derivative Works in Source or -Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, -each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) patent -license to make, have made, use, offer to sell, sell, import, and otherwise -transfer the Work, where such license applies only to those patent claims -licensable by such Contributor that are necessarily infringed by their -Contribution(s) alone or by combination of their Contribution(s) with the Work -to which such Contribution(s) was submitted. If You institute patent litigation -against any entity (including a cross-claim or counterclaim in a lawsuit) -alleging that the Work or a Contribution incorporated within the Work -constitutes direct or contributory patent infringement, then any patent licenses -granted to You under this License for that Work shall terminate as of the date -such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or -Derivative Works thereof in any medium, with or without modifications, and in -Source or Object form, provided that You meet the following conditions: - -1. You must give any other recipients of the Work or Derivative Works a copy -of this License; and - -2. You must cause any modified files to carry prominent notices stating that -You changed the files; and - -3. You must retain, in the Source form of any Derivative Works that You -distribute, all copyright, patent, trademark, and attribution notices from the -Source form of the Work, excluding those notices that do not pertain to any part -of the Derivative Works; and - -4. If the Work includes a "NOTICE" text file as part of its distribution, -then any Derivative Works that You distribute must include a readable copy of -the attribution notices contained within such NOTICE file, excluding those -notices that do not pertain to any part of the Derivative Works, in at least one -of the following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. - -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -provided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any -Contribution intentionally submitted for inclusion in the Work by You to the -Licensor shall be under the terms and conditions of this License, without any -additional terms or conditions. Notwithstanding the above, nothing herein shall -supersede or modify the terms of any separate license agreement you may have -executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, -trademarks, service marks, or product names of the Licensor, except as required -for reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in -writing, Licensor provides the Work (and each Contributor provides its -Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied, including, without limitation, any warranties -or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -PARTICULAR PURPOSE. You are solely responsible for determining the -appropriateness of using or redistributing the Work and assume any risks -associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in -tort (including negligence), contract, or otherwise, unless required by -applicable law (such as deliberate and grossly negligent acts) or agreed to in -writing, shall any Contributor be liable to You for damages, including any -direct, indirect, special, incidental, or consequential damages of any character -arising as a result of this License or out of the use or inability to use the -Work (including but not limited to damages for loss of goodwill, work stoppage, -computer failure or malfunction, or any and all other commercial damages or -losses), even if such Contributor has been advised of the possibility of such -damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or -Derivative Works thereof, You may choose to offer, and charge a fee for, -acceptance of support, warranty, indemnity, or other liability obligations -and/or rights consistent with this License. However, in accepting such -obligations, You may act only on Your own behalf and on Your sole -responsibility, not on behalf of any other Contributor, and only if You agree to -indemnify, defend, and hold each Contributor harmless for any liability incurred -by, or claims asserted against, such Contributor by reason of your accepting any -such warranty or additional liability. - -END OF TERMS AND CONDITIONS -APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same "printed page" as the copyright notice for easier identification within -third-party archives. -Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, -Version 2.0 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or -agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -or implied. See the License for the specific language governing permissions and -limitations under the License. -*************************************************************************** -%%The following software may be included in this product: -Apache Commons - commons-net-1.4.1.jar -Use of any of this software is governed by the terms of the license below: -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, -and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by -the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all -other entities that control, are controlled by, or are under common -control with that entity. For the purposes of this definition, -"control" means (i) the power, direct or indirect, to cause the -direction or management of such entity, whether by contract or -otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity -exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, -including but not limited to software source code, documentation -source, and configuration files. - -"Object" form shall mean any form resulting from mechanical -transformation or translation of a Source form, including but -not limited to compiled object code, generated documentation, -and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or -Object form, made available under the License, as indicated by a -copyright notice that is included in or attached to the work -(an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object -form, that is based on (or derived from) the Work and for which the -editorial revisions, annotations, elaborations, or other modifications -represent, as a whole, an original work of authorship. For the purposes -of this License, Derivative Works shall not include works that remain -separable from, or merely link (or bind by name) to the interfaces of, -the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including -the original version of the Work and any modifications or additions -to that Work or Derivative Works thereof, that is intentionally -submitted to Licensor for inclusion in the Work by the copyright owner -or by an individual or Legal Entity authorized to submit on behalf of -the copyright owner. For the purposes of this definition, "submitted" -means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, -and issue tracking systems that are managed by, or on behalf of, the -Licensor for the purpose of discussing and improving the Work, but -excluding communication that is conspicuously marked or otherwise -designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity -on behalf of whom a Contribution has been received by Licensor and -subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the -Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -(except as stated in this section) patent license to make, have made, -use, offer to sell, sell, import, and otherwise transfer the Work, -where such license applies only to those patent claims licensable -by such Contributor that are necessarily infringed by their -Contribution(s) alone or by combination of their Contribution(s) -with the Work to which such Contribution(s) was submitted. If You -institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work -or a Contribution incorporated within the Work constitutes direct -or contributory patent infringement, then any patent licenses -granted to You under this License for that Work shall terminate -as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the -Work or Derivative Works thereof in any medium, with or without -modifications, and in Source or Object form, provided that You -meet the following conditions: - -(a) You must give any other recipients of the Work or -Derivative Works a copy of this License; and - -(b) You must cause any modified files to carry prominent notices -stating that You changed the files; and - -(c) You must retain, in the Source form of any Derivative Works -that You distribute, all copyright, patent, trademark, and -attribution notices from the Source form of the Work, -excluding those notices that do not pertain to any part of -the Derivative Works; and - -(d) If the Work includes a "NOTICE" text file as part of its -distribution, then any Derivative Works that You distribute must -include a readable copy of the attribution notices contained -within such NOTICE file, excluding those notices that do not -pertain to any part of the Derivative Works, in at least one -of the following places: within a NOTICE text file distributed -as part of the Derivative Works; within the Source form or -documentation, if provided along with the Derivative Works; or, -within a display generated by the Derivative Works, if and -wherever such third-party notices normally appear. The contents -of the NOTICE file are for informational purposes only and -do not modify the License. You may add Your own attribution -notices within Derivative Works that You distribute, alongside -or as an addendum to the NOTICE text from the Work, provided -that such additional attribution notices cannot be construed -as modifying the License. - -You may add Your own copyright statement to Your modifications and -may provide additional or different license terms and conditions -for use, reproduction, or distribution of Your modifications, or -for any such Derivative Works as a whole, provided Your use, -reproduction, and distribution of the Work otherwise complies with -the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, -any Contribution intentionally submitted for inclusion in the Work -by You to the Licensor shall be under the terms and conditions of -this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify -the terms of any separate license agreement you may have executed -with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade -names, trademarks, service marks, or product names of the Licensor, -except as required for reasonable and customary use in describing the -origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or -agreed to in writing, Licensor provides the Work (and each -Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied, including, without limitation, any warranties or conditions -of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -PARTICULAR PURPOSE. You are solely responsible for determining the -appropriateness of using or redistributing the Work and assume any -risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, -whether in tort (including negligence), contract, or otherwise, -unless required by applicable law (such as deliberate and grossly -negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, -incidental, or consequential damages of any character arising as a -result of this License or out of the use or inability to use the -Work (including but not limited to damages for loss of goodwill, -work stoppage, computer failure or malfunction, or any and all -other commercial damages or losses), even if such Contributor -has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing -the Work or Derivative Works thereof, You may choose to offer, -and charge a fee for, acceptance of support, warranty, indemnity, -or other liability obligations and/or rights consistent with this -License. However, in accepting such obligations, You may act only -on Your own behalf and on Your sole responsibility, not on behalf -of any other Contributor, and only if You agree to indemnify, -defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason -of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following -boilerplate notice, with the fields enclosed by brackets "[]" -replaced with your own identifying information. (Don't include -the brackets!) The text should be enclosed in the appropriate -comment syntax for the file format. We also recommend that a -file or class name and description of purpose be included on the -same "printed page" as the copyright notice for easier -identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*************************************************************************** -%%The following software may be included in this product: -Jakarta Oro -Use of any of this software is governed by the terms of the license below: -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, -and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by -the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all -other entities that control, are controlled by, or are under common -control with that entity. For the purposes of this definition, -"control" means (i) the power, direct or indirect, to cause the -direction or management of such entity, whether by contract or -otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity -exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, -including but not limited to software source code, documentation -source, and configuration files. - -"Object" form shall mean any form resulting from mechanical -transformation or translation of a Source form, including but -not limited to compiled object code, generated documentation, -and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or -Object form, made available under the License, as indicated by a -copyright notice that is included in or attached to the work -(an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object -form, that is based on (or derived from) the Work and for which the -editorial revisions, annotations, elaborations, or other modifications -represent, as a whole, an original work of authorship. For the purposes -of this License, Derivative Works shall not include works that remain -separable from, or merely link (or bind by name) to the interfaces of, -the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including -the original version of the Work and any modifications or additions -to that Work or Derivative Works thereof, that is intentionally -submitted to Licensor for inclusion in the Work by the copyright owner -or by an individual or Legal Entity authorized to submit on behalf of -the copyright owner. For the purposes of this definition, "submitted" -means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, -and issue tracking systems that are managed by, or on behalf of, the -Licensor for the purpose of discussing and improving the Work, but -excluding communication that is conspicuously marked or otherwise -designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity -on behalf of whom a Contribution has been received by Licensor and -subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the -Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -(except as stated in this section) patent license to make, have made, -use, offer to sell, sell, import, and otherwise transfer the Work, -where such license applies only to those patent claims licensable -by such Contributor that are necessarily infringed by their -Contribution(s) alone or by combination of their Contribution(s) -with the Work to which such Contribution(s) was submitted. If You -institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work -or a Contribution incorporated within the Work constitutes direct -or contributory patent infringement, then any patent licenses -granted to You under this License for that Work shall terminate -as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the -Work or Derivative Works thereof in any medium, with or without -modifications, and in Source or Object form, provided that You -meet the following conditions: - -(a) You must give any other recipients of the Work or -Derivative Works a copy of this License; and - -(b) You must cause any modified files to carry prominent notices -stating that You changed the files; and - -(c) You must retain, in the Source form of any Derivative Works -that You distribute, all copyright, patent, trademark, and -attribution notices from the Source form of the Work, -excluding those notices that do not pertain to any part of -the Derivative Works; and - -(d) If the Work includes a "NOTICE" text file as part of its -distribution, then any Derivative Works that You distribute must -include a readable copy of the attribution notices contained -within such NOTICE file, excluding those notices that do not -pertain to any part of the Derivative Works, in at least one -of the following places: within a NOTICE text file distributed -as part of the Derivative Works; within the Source form or -documentation, if provided along with the Derivative Works; or, -within a display generated by the Derivative Works, if and -wherever such third-party notices normally appear. The contents -of the NOTICE file are for informational purposes only and -do not modify the License. You may add Your own attribution -notices within Derivative Works that You distribute, alongside -or as an addendum to the NOTICE text from the Work, provided -that such additional attribution notices cannot be construed -as modifying the License. - -You may add Your own copyright statement to Your modifications and -may provide additional or different license terms and conditions -for use, reproduction, or distribution of Your modifications, or -for any such Derivative Works as a whole, provided Your use, -reproduction, and distribution of the Work otherwise complies with -the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, -any Contribution intentionally submitted for inclusion in the Work -by You to the Licensor shall be under the terms and conditions of -this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify -the terms of any separate license agreement you may have executed -with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade -names, trademarks, service marks, or product names of the Licensor, -except as required for reasonable and customary use in describing the -origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or -agreed to in writing, Licensor provides the Work (and each -Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied, including, without limitation, any warranties or conditions -of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -PARTICULAR PURPOSE. You are solely responsible for determining the -appropriateness of using or redistributing the Work and assume any -risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, -whether in tort (including negligence), contract, or otherwise, -unless required by applicable law (such as deliberate and grossly -negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, -incidental, or consequential damages of any character arising as a -result of this License or out of the use or inability to use the -Work (including but not limited to damages for loss of goodwill, -work stoppage, computer failure or malfunction, or any and all -other commercial damages or losses), even if such Contributor -has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing -the Work or Derivative Works thereof, You may choose to offer, -and charge a fee for, acceptance of support, warranty, indemnity, -or other liability obligations and/or rights consistent with this -License. However, in accepting such obligations, You may act only -on Your own behalf and on Your sole responsibility, not on behalf -of any other Contributor, and only if You agree to indemnify, -defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason -of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following -boilerplate notice, with the fields enclosed by brackets "[]" -replaced with your own identifying information. (Don't include -the brackets!) The text should be enclosed in the appropriate -comment syntax for the file format. We also recommend that a -file or class name and description of purpose be included on the -same "printed page" as the copyright notice for easier -identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*************************************************************************** -%%The following software may be included in this product: -Jsch -Use of any of this software is governed by the terms of the license below: -JSch 0.0.* was released under the GNU LGPL license. Later, we have switched -over to a BSD-style license. - ------------------------------------------------------------------------------- -Copyright (c) 2002,2003,2004,2005,2006,2007,2008 Atsuhiko Yamanaka, JCraft,Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. 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. - -3. The names of the authors may not be used to endorse or promote products -derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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. -Additional License(s) -LICENSE.txt:JSch 0.0.* was released under the GNU LGPL license. -Later, we have switched -LICENSE.txt:over to a BSD-style license. -*************************************************************************** -%%The following software may be included in this product: -Expect4j -Use of any of this software is governed by the terms of the license below: -Apache License, Version 2.0 - -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -"submitted" means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this -License, each Contributor hereby grants to You a perpetual, worldwide, -non-exclusive, no-charge, royalty-free, irrevocable copyright license to -reproduce, prepare Derivative Works of, publicly display, publicly perform, -sublicense, and distribute the Work and such Derivative Works in Source or -Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, -each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) patent -license to make, have made, use, offer to sell, sell, import, and otherwise -transfer the Work, where such license applies only to those patent claims -licensable by such Contributor that are necessarily infringed by their -Contribution(s) alone or by combination of their Contribution(s) with the Work -to which such Contribution(s) was submitted. If You institute patent litigation -against any entity (including a cross-claim or counterclaim in a lawsuit) -alleging that the Work or a Contribution incorporated within the Work -constitutes direct or contributory patent infringement, then any patent licenses -granted to You under this License for that Work shall terminate as of the date -such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or -Derivative Works thereof in any medium, with or without modifications, and in -Source or Object form, provided that You meet the following conditions: - -1. You must give any other recipients of the Work or Derivative Works a copy -of this License; and - -2. You must cause any modified files to carry prominent notices stating that -You changed the files; and - -3. You must retain, in the Source form of any Derivative Works that You -distribute, all copyright, patent, trademark, and attribution notices from the -Source form of the Work, excluding those notices that do not pertain to any part -of the Derivative Works; and - -4. If the Work includes a "NOTICE" text file as part of its distribution, -then any Derivative Works that You distribute must include a readable copy of -the attribution notices contained within such NOTICE file, excluding those -notices that do not pertain to any part of the Derivative Works, in at least one -of the following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. - -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -provided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any -Contribution intentionally submitted for inclusion in the Work by You to the -Licensor shall be under the terms and conditions of this License, without any -additional terms or conditions. Notwithstanding the above, nothing herein shall -supersede or modify the terms of any separate license agreement you may have -executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, -trademarks, service marks, or product names of the Licensor, except as required -for reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in -writing, Licensor provides the Work (and each Contributor provides its -Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied, including, without limitation, any warranties -or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -PARTICULAR PURPOSE. You are solely responsible for determining the -appropriateness of using or redistributing the Work and assume any risks -associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in -tort (including negligence), contract, or otherwise, unless required by -applicable law (such as deliberate and grossly negligent acts) or agreed to in -writing, shall any Contributor be liable to You for damages, including any -direct, indirect, special, incidental, or consequential damages of any character -arising as a result of this License or out of the use or inability to use the -Work (including but not limited to damages for loss of goodwill, work stoppage, -computer failure or malfunction, or any and all other commercial damages or -losses), even if such Contributor has been advised of the possibility of such -damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or -Derivative Works thereof, You may choose to offer, and charge a fee for, -acceptance of support, warranty, indemnity, or other liability obligations -and/or rights consistent with this License. However, in accepting such -obligations, You may act only on Your own behalf and on Your sole -responsibility, not on behalf of any other Contributor, and only if You agree to -indemnify, defend, and hold each Contributor harmless for any liability incurred -by, or claims asserted against, such Contributor by reason of your accepting any -such warranty or additional liability. - -END OF TERMS AND CONDITIONS -APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same "printed page" as the copyright notice for easier identification within -third-party archives. -Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, -Version 2.0 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or -agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -or implied. See the License for the specific language governing permissions and -limitations under the License. -Apache Projects - -* HTTP Server -* ActiveMQ -* Ant -* APR -* Archiva -* Beehive -* Cayenne -* Cocoon -* Commons -* Continuum -* CXF -* DB -* Directory -* Excalibur -* Felix -* Forrest -* Geronimo -* Gump -* Hadoop -* Harmony -* HiveMind -* HttpComponents -* iBATIS -* Incubator -* Jackrabbit -* Jakarta -* James -* Labs -* Lenya -* Logging -* Lucene -* Maven -* Mina -* MyFaces -* ODE -* OFBiz -* OpenEJB -* OpenJPA -* Perl -* POI -* Portals -* Roller -* Santuario -* ServiceMix -* Shale -* SpamAssassin -* STDCXX -* Struts -* Synapse -* Tapestry -* TCL -* Tiles -* Tomcat -* Turbine -* Velocity -* Wicket -* Web Services -* Xalan -* Xerces -* XML -* XMLBeans -* XML Graphics - -Foundation - -* FAQ -* Licenses -* News -* Public Records -* Sponsorship -* Donations -* Thanks -* Contact - -Foundation Projects - -* Conferences -* Infrastructure -* JCP - -How it works - -* Introduction -* Meritocracy -* Structure -* Roles -* Collaboration -* Infrastructure -* Incubator -* Other entities -* Glossary -* Voting - -Get Involved - -* Mailing Lists -* Version Control -* Developer Info - -Download - -* from a mirror - -Related Sites - -* ApacheCon -* Bookstore -* Feathercast -* PlanetApache - -Copyright © 2008 The Apache Software Foundation, Licensed under the Apache -License, Version 2.0. -*************************************************************************** -%%The following software may be included in this product: -FreeHost3270 -Use of any of this software is governed by the terms of the license below: -GNU LESSER GENERAL PUBLIC LICENSE - -Version 2.1, February 1999 - -Copyright (C) 1991, 1999 Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts -as the successor of the GNU Library Public License, version 2, hence -the version number 2.1.] -Preamble - -The licenses for most software are designed to take away your freedom to share and change it. By -contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - -This license, the Lesser General Public License, applies to some specially designated software -packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. -You can use it too, but we suggest you first think carefully about whether this license or the ordinary -General Public License is the better strategy to use in any particular case, based on the explanations -below. - -When we speak of free software, we are referring to freedom of use, not price. Our General Public -Licenses are designed to make sure that you have the freedom to distribute copies of free software (and -charge for this service if you wish); that you receive source code or can get it if you want it; that you -can change the software and use pieces of it in new free programs; and that you are informed that you -can do these things. - -To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or -to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if -you distribute copies of the library or if you modify it. - -For example, if you distribute copies of the library, whether gratis or for a fee, you must give the -recipients all the rights that we gave you. You must make sure that they, too, receive or can get the -source code. If you link other code with the library, you must provide complete object files to the -recipients, so that they can relink them with the library after making changes to the library and -recompiling it. And you must show them these terms so they know their rights. - -We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this -license, which gives you legal permission to copy, distribute and/or modify the library. - -To protect each distributor, we want to make it very clear that there is no warranty for the free library. -Also, if the library is modified by someone else and passed on, the recipients should know that what -they have is not the original version, so that the original author's reputation will not be affected by -problems that might be introduced by others. - -Finally, software patents pose a constant threat to the existence of any free program. We wish to make -sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive -license from a patent holder. Therefore, we insist that any patent license obtained for a version of the -library must be consistent with the full freedom of use specified in this license. - -Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. -This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite -different from the ordinary General Public License. We use this license for certain libraries in order to -permit linking those libraries into non-free programs. - -When a program is linked with a library, whether statically or using a shared library, the combination of -the two is legally speaking a combined work, a derivative of the original library. The ordinary General -Public License therefore permits such linking only if the entire combination fits its criteria of freedom. -The Lesser General Public License permits more lax criteria for linking other code with the library. - -We call this license the "Lesser" General Public License because it does Less to protect the user's -freedom than the ordinary General Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages are the reason we use the -ordinary General Public License for many libraries. However, the Lesser license provides advantages in -certain special circumstances. - -For example, on rare occasions, there may be a special need to encourage the widest possible use of a -certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free library does the same job as widely used -non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so -we use the Lesser General Public License. - -In other cases, permission to use a particular library in non-free programs enables a greater number of -people to use a large body of free software. For example, permission to use the GNU C Library in non- -free programs enables many more people to use the whole GNU operating system, as well as its variant, -the GNU/Linux operating system. - -Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that -the user of a program that is linked with the Library has the freedom and the wherewithal to run that -program using a modified version of the Library. - -The precise terms and conditions for copying, distribution and modification follow. Pay close attention -to the difference between a "work based on the library" and a "work that uses the library". The former -contains code derived from the library, whereas the latter must be combined with the library in order to -run. - -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -0. This License Agreement applies to any software library or other program which contains a notice -placed by the copyright holder or other authorized party saying it may be distributed under the terms -of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". - -A "library" means a collection of software functions and/or data prepared so as to be conveniently -linked with application programs (which use some of those functions and data) to form executables. - -The "Library", below, refers to any such software library or work which has been distributed under these -terms. A "work based on the Library" means either the Library or any derivative work under copyright -law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications -and/or translated straightforwardly into another language. (Hereinafter, translation is included without -limitation in the term "modification".) - -"Source code" for a work means the preferred form of the work for making modifications to it. For a -library, complete source code means all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation and installation of the library. - -Activities other than copying, distribution and modification are not covered by this License; they are -outside its scope. The act of running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based on the Library (independent of -the use of the Library in a tool for writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - -1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, -in any medium, provided that you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this -License and to the absence of any warranty; and distribute a copy of this License along with the Library. - -You may charge a fee for the physical act of transferring a copy, and you may at your option offer -warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based -on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, -provided that you also meet all of these conditions: - -a) The modified work must itself be a software library. -b) You must cause the files modified to carry prominent notices stating that you changed the files and -the date of any change. -c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms -of this License. -d) If a facility in the modified Library refers to a function or a table of data to be supplied by an -application program that uses the facility, other than as an argument passed when the facility is -invoked, then you must make a good faith effort to ensure that, in the event an application does not -supply such function or table, the facility still operates, and performs whatever part of its purpose -remains meaningful. -(For example, a function in a library to compute square roots has a purpose that is entirely well- -defined independent of the application. Therefore, Subsection 2d requires that any application- -supplied function or table used by this function must be optional: if the application does not supply it, -the square root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If identifiable sections of that work are not -derived from the Library, and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those sections when you distribute them as -separate works. But when you distribute the same sections as part of a whole which is a work based on -the Library, the distribution of the whole must be on the terms of this License, whose permissions for -other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. -Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by -you; rather, the intent is to exercise the right to control the distribution of derivative or collective works -based on the Library. - -In addition, mere aggregation of another work not based on the Library with the Library (or with a work -based on the Library) on a volume of a storage or distribution medium does not bring the other work -under the scope of this License. - -3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to -a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that -they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer -version than version 2 of the ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in these notices. - -Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General -Public License applies to all subsequent copies and derivative works made from that copy. - -This option is useful when you wish to copy part of the code of the Library into a program that is not a -library. - -4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object -code or executable form under the terms of Sections 1 and 2 above provided that you accompany it -with the complete corresponding machine-readable source code, which must be distributed under the -terms of Sections 1 and 2 above on a medium customarily used for software interchange. - -If distribution of object code is made by offering access to copy from a designated place, then offering -equivalent access to copy the source code from the same place satisfies the requirement to distribute -the source code, even though third parties are not compelled to copy the source along with the object -code. - -5. A program that contains no derivative of any portion of the Library, but is designed to work with the -Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in -isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. - -However, linking a "work that uses the Library" with the Library creates an executable that is a -derivative of the Library (because it contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. Section 6 states terms for distribution of -such executables. - -When a "work that uses the Library" uses material from a header file that is part of the Library, the -object code for the work may be a derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be linked without the Library, or if the work -is itself a library. The threshold for this to be true is not precisely defined by law. - -If such an object file uses only numerical parameters, data structure layouts and accessors, and small -macros and small inline functions (ten lines or less in length), then the use of the object file is -unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object -code plus portions of the Library will still fall under Section 6.) - -Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work -under the terms of Section 6. Any executables containing that work also fall under Section 6, whether -or not they are linked directly with the Library itself. - -6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" -with the Library to produce a work containing portions of the Library, and distribute that work under -terms of your choice, provided that the terms permit modification of the work for the customer's own -use and reverse engineering for debugging such modifications. - -You must give prominent notice with each copy of the work that the Library is used in it and that the -Library and its use are covered by this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the copyright notice for the Library -among them, as well as a reference directing the user to the copy of this License. Also, you must do -one of these things: - -a) Accompany the work with the complete corresponding machine-readable source code for the Library -including whatever changes were used in the work (which must be distributed under Sections 1 and 2 -above); and, if the work is an executable linked with the Library, with the complete machine-readable -"work that uses the Library", as object code and/or source code, so that the user can modify the Library -and then relink to produce a modified executable containing the modified Library. (It is understood that -the user who changes the contents of definitions files in the Library will not necessarily be able to -recompile the application to use the modified definitions.) -b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one -that (1) uses at run time a copy of the library already present on the user's computer system, rather -than copying library functions into the executable, and (2) will operate properly with a modified version -of the library, if the user installs one, as long as the modified version is interface-compatible with the -version that the work was made with. -c) Accompany the work with a written offer, valid for at least three years, to give the same user the -materials specified in Subsection 6a, above, for a charge no more than the cost of performing this -distribution. -d) If distribution of the work is made by offering access to copy from a designated place, offer -equivalent access to copy the above specified materials from the same place. -e) Verify that the user has already received a copy of these materials or that you have already sent this -user a copy. -For an executable, the required form of the "work that uses the Library" must include any data and -utility programs needed for reproducing the executable from it. However, as a special exception, the -materials to be distributed need not include anything that is normally distributed (in either source or -binary form) with the major components (compiler, kernel, and so on) of the operating system on which -the executable runs, unless that component itself accompanies the executable. - -It may happen that this requirement contradicts the license restrictions of other proprietary libraries -that do not normally accompany the operating system. Such a contradiction means you cannot use both -them and the Library together in an executable that you distribute. - -7. You may place library facilities that are a work based on the Library side-by-side in a single library -together with other library facilities not covered by this License, and distribute such a combined library, -provided that the separate distribution of the work based on the Library and of the other library -facilities is otherwise permitted, and provided that you do these two things: - -a) Accompany the combined library with a copy of the same work based on the Library, uncombined -with any other library facilities. This must be distributed under the terms of the Sections above. -b) Give prominent notice with the combined library of the fact that part of it is a work based on the -Library, and explaining where to find the accompanying uncombined form of the same work. -8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly -provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute -the Library is void, and will automatically terminate your rights under this License. However, parties -who have received copies, or rights, from you under this License will not have their licenses terminated -so long as such parties remain in full compliance. - -9. You are not required to accept this License, since you have not signed it. However, nothing else -grants you permission to modify or distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library -(or any work based on the Library), you indicate your acceptance of this License to do so, and all its -terms and conditions for copying, distributing or modifying the Library or works based on it. - -10. Each time you redistribute the Library (or any work based on the Library), the recipient -automatically receives a license from the original licensor to copy, distribute, link with or modify the -Library subject to these terms and conditions. You may not impose any further restrictions on the -recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by -third parties with this License. - -11. If, as a consequence of a court judgment or allegation of patent infringement or for any other -reason (not limited to patent issues), conditions are imposed on you (whether by court order, -agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the -conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations -under this License and any other pertinent obligations, then as a consequence you may not distribute -the Library at all. For example, if a patent license would not permit royalty-free redistribution of the -Library by all those who receive copies directly or indirectly through you, then the only way you could -satisfy both it and this License would be to refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any particular circumstance, the -balance of the section is intended to apply, and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any patents or other property right claims -or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of -the free software distribution system which is implemented by public license practices. Many people -have made generous contributions to the wide range of software distributed through that system in -reliance on consistent application of that system; it is up to the author/donor to decide if he or she is -willing to distribute software through any other system and a licensee cannot impose that choice. - -This section is intended to make thoroughly clear what is believed to be a consequence of the rest of -this License. - -12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by -copyrighted interfaces, the original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, so that distribution is -permitted only in or among countries not thus excluded. In such case, this License incorporates the -limitation as if written in the body of this License. - -13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public -License from time to time. Such new versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library specifies a version number of this -License which applies to it and "any later version", you have the option of following the terms and -conditions either of that version or of any later version published by the Free Software Foundation. If -the Library does not specify a license version number, you may choose any version ever published by -the Free Software Foundation. - -14. If you wish to incorporate parts of the Library into other free programs whose distribution -conditions are incompatible with these, write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals of preserving the free status of -all derivatives of our free software and of promoting the sharing and reuse of software generally. - -NO WARRANTY - -15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, -TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE -COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF -ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY -AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU -ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY -COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS -PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL -OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY -(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES -SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER -SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Libraries - -If you develop a new library, and you want it to be of the greatest possible use to the public, we -recommend making it free software that everyone can redistribute and change. You can do so by -permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General -Public License). - -To apply these terms, attach the following notices to the library. It is safest to attach them to the start -of each source file to most effectively convey the exclusion of warranty; and each file should have at -least the "copyright" line and a pointer to where the full notice is found. - -one line to give the library's name and an idea of what it does. -Copyright (C) year name of author - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your school, if any, to sign a -"copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: - -Yoyodyne, Inc., hereby disclaims all copyright interest in -the library `Frob' (a library for tweaking knobs) written -by James Random Hacker. - -signature of Ty Coon, 1 April 1990 -Ty Coon, President of Vice -That's all there is to it! -*************************************************************************** -%%The following software may be included in this product: -Boo -Use of any of this software is governed by the terms of the license below: -Copyright (c) 2003, 2004, Rodrigo B. de Oliveira (rbo@acm.org) -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 Rodrigo B. de Oliveira 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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. -*************************************************************************** - - -DO NOT TRANSLATE OR LOCALIZE -*************************************************************************** -%%The following software may be included in this product: -Groovy Scripting Language -Use of any of this software is governed by the terms of the license below: -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -"submitted" means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this -License, each Contributor hereby grants to You a perpetual, worldwide, -non-exclusive, no-charge, royalty-free, irrevocable copyright license to -reproduce, prepare Derivative Works of, publicly display, publicly perform, -sublicense, and distribute the Work and such Derivative Works in Source or -Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, -each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) patent -license to make, have made, use, offer to sell, sell, import, and otherwise -transfer the Work, where such license applies only to those patent claims -licensable by such Contributor that are necessarily infringed by their -Contribution(s) alone or by combination of their Contribution(s) with the Work -to which such Contribution(s) was submitted. If You institute patent litigation -against any entity (including a cross-claim or counterclaim in a lawsuit) -alleging that the Work or a Contribution incorporated within the Work -constitutes direct or contributory patent infringement, then any patent licenses -granted to You under this License for that Work shall terminate as of the date -such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or -Derivative Works thereof in any medium, with or without modifications, and in -Source or Object form, provided that You meet the following conditions: - -1. You must give any other recipients of the Work or Derivative Works a copy -of this License; and - -2. You must cause any modified files to carry prominent notices stating that -You changed the files; and - -3. You must retain, in the Source form of any Derivative Works that You -distribute, all copyright, patent, trademark, and attribution notices from the -Source form of the Work, excluding those notices that do not pertain to any part -of the Derivative Works; and - -4. If the Work includes a "NOTICE" text file as part of its distribution, -then any Derivative Works that You distribute must include a readable copy of -the attribution notices contained within such NOTICE file, excluding those -notices that do not pertain to any part of the Derivative Works, in at least one -of the following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. - -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -prov ided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any -Contribution intentionally submitted for inclusion in the Work by You to the -Licensor shall be under the terms and conditions of this License, without any -additional terms or conditions. Notwithstanding the above, nothing herein shall -supersede or modify the terms of any separate license agreement you may have -executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, -trademarks, service marks, or product names of the Licensor, except as required -for reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in -writing, Licensor provides the Work (and each Contributor provides its -Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied, including, without limitation, any warranties -or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -PARTICULAR PURPOSE. You are solely responsible for determining the -appropriateness of using or redistributing the Work and assume any risks -associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in -tort (including negligence), contract, or otherwise, unless required by -applicable law (such as deliberate and grossly negligent acts) or agreed to in -writing, shall any Contributor be liable to You for damages, including any -direct, indirect, special, incidental, or consequential damages of any character -arising as a result of this License or out of the use or inability to use the -Work (including but not limited to damages for loss of goodwill, work stoppage, -computer failure or malfunction, or any and all other commercial damages or -losses), even if such Contributor has been advised of the possibility of such -damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or -Derivative Works thereof, You may choose to offer, and charge a fee for, -acceptance of support, warranty, indemnity, or other liability obligations -and/or rights consistent with this License. However, in accepting such -obligations, You may act only on Your own behalf and on Your sole -responsibility, not on behalf of any other Contributor, and only if You agree to -indemnify, defend, and hold each Contributor harmless for any liability incurred -by, or claims asserted against, such Contributor by reason of your accepting any -such warranty or additional liability. - -END OF TERMS AND CONDITIONS -APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same "printed page" as the copyright notice for easier identification within -third-party archives. -Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, -Version 2.0 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or -agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -or implied. See the License for the specific language governing permissions and -limitations under the License. -*************************************************************************** -%%The following software may be included in this product: -Apache Commons Pool -Use of any of this software is governed by the terms of the license below: -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, -and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by -the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all -other entities that control, are controlled by, or are under common -control with that entity. For the purposes of this definition, -"control" means (i) the power, direct or indirect, to cause the -direction or management of such entity, whether by contract or -otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity -exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, -including but not limited to software source code, documentation -source, and configuration files. - -"Object" form shall mean any form resulting from mechanical -transformation or translation of a Source form, including but -not limited to compiled object code, generated documentation, -and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or -Object form, made available under the License, as indicated by a -copyright notice that is included in or attached to the work -(an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object -form, that is based on (or derived from) the Work and for which the -editorial revisions, annotations, elaborations, or other modifications -represent, as a whole, an original work of authorship. For the purposes -of this License, Derivative Works shall not include works that remain -separable from, or merely link (or bind by name) to the interfaces of, -the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including -the original version of the Work and any modifications or additions -to that Work or Derivative Works thereof, that is intentionally -submitted to Licensor for inclusion in the Work by the copyright owner -or by an individual or Legal Entity authorized to submit on behalf of -the copyright owner. For the purposes of this definition, "submitted" -means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, -and issue tracking systems that are managed by, or on behalf of, the -Licensor for the purpose of discussing and improving the Work, but -excluding communication that is conspicuously marked or otherwise -designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity -on behalf of whom a Contribution has been received by Licensor and -subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the -Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -(except as stated in this section) patent license to make, have made, -use, offer to sell, sell, import, and otherwise transfer the Work, -where such license applies only to those patent claims licensable -by such Contributor that are necessarily infringed by their -Contribution(s) alone or by combination of their Contribution(s) -with the Work to which such Contribution(s) was submitted. If You -institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work -or a Contribution incorporated within the Work constitutes direct -or contributory patent infringement, then any patent licenses -granted to You under this License for that Work shall terminate -as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the -Work or Derivative Works thereof in any medium, with or without -modifications, and in Source or Object form, provided that You -meet the following conditions: - -(a) You must give any other recipients of the Work or -Derivative Works a copy of this License; and - -(b) You must cause any modified files to carry prominent notices -stating that You changed the files; and - -(c) You must retain, in the Source form of any Derivative Works -that You distribute, all copyright, patent, trademark, and -attribution notices from the Source form of the Work, -excluding those notices that do not pertain to any part of -the Derivative Works; and - -(d) If the Work includes a "NOTICE" text file as part of its -distribution, then any Derivative Works that You distribute must -include a readable copy of the attribution notices contained -within such NOTICE file, excluding those notices that do not -pertain to any part of the Derivative Works, in at least one -of the following places: within a NOTICE text file distributed -as part of the Derivative Works; within the Source form or -documentation, if provided along with the Derivative Works; or, -within a display generated by the Derivative Works, if and -wherever such third-party notices normally appear. The contents -of the NOTICE file are for informational purposes only and -do not modify the License. You may add Your own attribution -notices within Derivative Works that You distribute, alongside -or as an addendum to the NOTICE text from the Work, provided -that such additional attribution notices cannot be construed -as modifying the License. - -You may add Your own copyright statement to Your modifications and -may provide additional or different license terms and conditions -for use, reproduction, or distribution of Your modifications, or -for any such Derivative Works as a whole, provided Your use, -reproduction, and distribution of the Work otherwise complies with -the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, -any Contribution intentionally submitted for inclusion in the Work -by You to the Licensor shall be under the terms and conditions of -this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify -the terms of any separate license agreement you may have executed -with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade -names, trademarks, service marks, or product names of the Licensor, -except as required for reasonable and customary use in describing the -origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or -agreed to in writing, Licensor provides the Work (and each -Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied, including, without limitation, any warranties or conditions -of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -PARTICULAR PURPOSE. You are solely responsible for determining the -appropriateness of using or redistributing the Work and assume any -risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, -whether in tort (including negligence), contract, or otherwise, -unless required by applicable law (such as deliberate and grossly -negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, -incidental, or consequential damages of any character arising as a -result of this License or out of the use or inability to use the -Work (including but not limited to damages for loss of goodwill, -work stoppage, computer failure or malfunction, or any and all -other commercial damages or losses), even if such Contributor -has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing -the Work or Derivative Works thereof, You may choose to offer, -and charge a fee for, acceptance of support, warranty, indemnity, -or other liability obligations and/or rights consistent with this -License. However, in accepting such obligations, You may act only -on Your own behalf and on Your sole responsibility, not on behalf -of any other Contributor, and only if You agree to indemnify, -defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason -of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following -boilerplate notice, with the fields enclosed by brackets "[]" -replaced with your own identifying information. (Don't include -the brackets!) The text should be enclosed in the appropriate -comment syntax for the file format. We also recommend that a -file or class name and description of purpose be included on the -same "printed page" as the copyright notice for easier -identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*************************************************************************** -%%The following software may be included in this product: -HSQL Database Engine -Use of any of this software is governed by the terms of the license below: -COPYRIGHTS AND LICENSES - -ORIGINAL LICENSE (a.k.a. "hypersonic_lic.txt") - -For content, code, and products originally developed by Thomas Mueller and the -Hypersonic SQL Group: - -Copyright (c) 1995-2000 by the Hypersonic SQL Group. -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 Hypersonic SQL Group 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE HYPERSONIC SQL GROUP, -OR CONTRIBUTORS 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. - -This software consists of voluntary contributions made by many individuals on -behalf of the -Hypersonic SQL Group. - - - -For work added by the HSQL Development Group (a.k.a. hsqldb_lic.txt): -Copyright (c) 2001-2005, The HSQL Development Group -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 HSQL Development Group 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 HSQL DEVELOPMENT GROUP, HSQLDB.ORG, -OR CONTRIBUTORS 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. -*************************************************************************** -%%The following software may be included in this product: -Derby -Use of any of this software is governed by the terms of the license below: -Apache License, Version 2.0 - -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -"submitted" means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this -License, each Contributor hereby grants to You a perpetual, worldwide, -non-exclusive, no-charge, royalty-free, irrevocable copyright license to -reproduce, prepare Derivative Works of, publicly display, publicly perform, -sublicense, and distribute the Work and such Derivative Works in Source or -Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, -each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) patent -license to make, have made, use, offer to sell, sell, import, and otherwise -transfer the Work, where such license applies only to those patent claims -licensable by such Contributor that are necessarily infringed by their -Contribution(s) alone or by combination of their Contribution(s) with the Work -to which such Contribution(s) was submitted. If You institute patent litigation -against any entity (including a cross-claim or counterclaim in a lawsuit) -alleging that the Work or a Contribution incorporated within the Work -constitutes direct or contributory patent infringement, then any patent licenses -granted to You under this License for that Work shall terminate as of the date -such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or -Derivative Works thereof in any medium, with or without modifications, and in -Source or Object form, provided that You meet the following conditions: - -1. You must give any other recipients of the Work or Derivative Works a copy -of this License; and - -2. You must cause any modified files to carry prominent notices stating that -You changed the files; and - -3. You must retain, in the Source form of any Derivative Works that You -distribute, all copyright, patent, trademark, and attribution notices from the -Source form of the Work, excluding those notices that do not pertain to any part -of the Derivative Works; and - -4. If the Work includes a "NOTICE" text file as part of its distribution, -then any Derivative Works that You distribute must include a readable copy of -the attribution notices contained within such NOTICE file, excluding those -notices that do not pertain to any part of the Derivative Works, in at least one -of the following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. - -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -provided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any -Contribution intentionally submitted for inclusion in the Work by You to the -Licensor shall be under the terms and conditions of this License, without any -additional terms or conditions. Notwithstanding the above, nothing herein shall -supersede or modify the terms of any separate license agreement you may have -executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, -trademarks, service marks, or product names of the Licensor, except as required -for reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in -writing, Licensor provides the Work (and each Contributor provides its -Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied, including, without limitation, any warranties -or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -PARTICULAR PURPOSE. You are solely responsible for determining the -appropriateness of using or redistributing the Work and assume any risks -associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in -tort (including negligence), contract, or otherwise, unless required by -applicable law (such as deliberate and grossly negligent acts) or agreed to in -writing, shall any Contributor be liable to You for damages, including any -direct, indirect, special, incidental, or consequential damages of any character -arising as a result of this License or out of the use or inability to use the -Work (including but not limited to damages for loss of goodwill, work stoppage, -computer failure or malfunction, or any and all other commercial damages or -losses), even if such Contributor has been advised of the possibility of such -damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or -Derivative Works thereof, You may choose to offer, and charge a fee for, -acceptance of support, warranty, indemnity, or other liability obligations -and/or rights consistent with this License. However, in accepting such -obligations, You may act only on Your own behalf and on Your sole -responsibility, not on behalf of any other Contributor, and only if You agree to -indemnify, defend, and hold each Contributor harmless for any liability incurred -by, or claims asserted against, such Contributor by reason of your accepting any -such warranty or additional liability. - -END OF TERMS AND CONDITIONS -APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same "printed page" as the copyright notice for easier identification within -third-party archives. -Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, -Version 2.0 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or -agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -or implied. See the License for the specific language governing permissions and -limitations under the License. -*************************************************************************** -%%The following software may be included in this product: -Apache Commons - commons-net-1.4.1.jar -Use of any of this software is governed by the terms of the license below: -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, -and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by -the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all -other entities that control, are controlled by, or are under common -control with that entity. For the purposes of this definition, -"control" means (i) the power, direct or indirect, to cause the -direction or management of such entity, whether by contract or -otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity -exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, -including but not limited to software source code, documentation -source, and configuration files. - -"Object" form shall mean any form resulting from mechanical -transformation or translation of a Source form, including but -not limited to compiled object code, generated documentation, -and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or -Object form, made available under the License, as indicated by a -copyright notice that is included in or attached to the work -(an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object -form, that is based on (or derived from) the Work and for which the -editorial revisions, annotations, elaborations, or other modifications -represent, as a whole, an original work of authorship. For the purposes -of this License, Derivative Works shall not include works that remain -separable from, or merely link (or bind by name) to the interfaces of, -the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including -the original version of the Work and any modifications or additions -to that Work or Derivative Works thereof, that is intentionally -submitted to Licensor for inclusion in the Work by the copyright owner -or by an individual or Legal Entity authorized to submit on behalf of -the copyright owner. For the purposes of this definition, "submitted" -means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, -and issue tracking systems that are managed by, or on behalf of, the -Licensor for the purpose of discussing and improving the Work, but -excluding communication that is conspicuously marked or otherwise -designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity -on behalf of whom a Contribution has been received by Licensor and -subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the -Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -(except as stated in this section) patent license to make, have made, -use, offer to sell, sell, import, and otherwise transfer the Work, -where such license applies only to those patent claims licensable -by such Contributor that are necessarily infringed by their -Contribution(s) alone or by combination of their Contribution(s) -with the Work to which such Contribution(s) was submitted. If You -institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work -or a Contribution incorporated within the Work constitutes direct -or contributory patent infringement, then any patent licenses -granted to You under this License for that Work shall terminate -as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the -Work or Derivative Works thereof in any medium, with or without -modifications, and in Source or Object form, provided that You -meet the following conditions: - -(a) You must give any other recipients of the Work or -Derivative Works a copy of this License; and - -(b) You must cause any modified files to carry prominent notices -stating that You changed the files; and - -(c) You must retain, in the Source form of any Derivative Works -that You distribute, all copyright, patent, trademark, and -attribution notices from the Source form of the Work, -excluding those notices that do not pertain to any part of -the Derivative Works; and - -(d) If the Work includes a "NOTICE" text file as part of its -distribution, then any Derivative Works that You distribute must -include a readable copy of the attribution notices contained -within such NOTICE file, excluding those notices that do not -pertain to any part of the Derivative Works, in at least one -of the following places: within a NOTICE text file distributed -as part of the Derivative Works; within the Source form or -documentation, if provided along with the Derivative Works; or, -within a display generated by the Derivative Works, if and -wherever such third-party notices normally appear. The contents -of the NOTICE file are for informational purposes only and -do not modify the License. You may add Your own attribution -notices within Derivative Works that You distribute, alongside -or as an addendum to the NOTICE text from the Work, provided -that such additional attribution notices cannot be construed -as modifying the License. - -You may add Your own copyright statement to Your modifications and -may provide additional or different license terms and conditions -for use, reproduction, or distribution of Your modifications, or -for any such Derivative Works as a whole, provided Your use, -reproduction, and distribution of the Work otherwise complies with -the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, -any Contribution intentionally submitted for inclusion in the Work -by You to the Licensor shall be under the terms and conditions of -this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify -the terms of any separate license agreement you may have executed -with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade -names, trademarks, service marks, or product names of the Licensor, -except as required for reasonable and customary use in describing the -origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or -agreed to in writing, Licensor provides the Work (and each -Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied, including, without limitation, any warranties or conditions -of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -PARTICULAR PURPOSE. You are solely responsible for determining the -appropriateness of using or redistributing the Work and assume any -risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, -whether in tort (including negligence), contract, or otherwise, -unless required by applicable law (such as deliberate and grossly -negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, -incidental, or consequential damages of any character arising as a -result of this License or out of the use or inability to use the -Work (including but not limited to damages for loss of goodwill, -work stoppage, computer failure or malfunction, or any and all -other commercial damages or losses), even if such Contributor -has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing -the Work or Derivative Works thereof, You may choose to offer, -and charge a fee for, acceptance of support, warranty, indemnity, -or other liability obligations and/or rights consistent with this -License. However, in accepting such obligations, You may act only -on Your own behalf and on Your sole responsibility, not on behalf -of any other Contributor, and only if You agree to indemnify, -defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason -of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following -boilerplate notice, with the fields enclosed by brackets "[]" -replaced with your own identifying information. (Don't include -the brackets!) The text should be enclosed in the appropriate -comment syntax for the file format. We also recommend that a -file or class name and description of purpose be included on the -same "printed page" as the copyright notice for easier -identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*************************************************************************** -%%The following software may be included in this product: -Jakarta Oro -Use of any of this software is governed by the terms of the license below: -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, -and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by -the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all -other entities that control, are controlled by, or are under common -control with that entity. For the purposes of this definition, -"control" means (i) the power, direct or indirect, to cause the -direction or management of such entity, whether by contract or -otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity -exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, -including but not limited to software source code, documentation -source, and configuration files. - -"Object" form shall mean any form resulting from mechanical -transformation or translation of a Source form, including but -not limited to compiled object code, generated documentation, -and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or -Object form, made available under the License, as indicated by a -copyright notice that is included in or attached to the work -(an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object -form, that is based on (or derived from) the Work and for which the -editorial revisions, annotations, elaborations, or other modifications -represent, as a whole, an original work of authorship. For the purposes -of this License, Derivative Works shall not include works that remain -separable from, or merely link (or bind by name) to the interfaces of, -the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including -the original version of the Work and any modifications or additions -to that Work or Derivative Works thereof, that is intentionally -submitted to Licensor for inclusion in the Work by the copyright owner -or by an individual or Legal Entity authorized to submit on behalf of -the copyright owner. For the purposes of this definition, "submitted" -means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, -and issue tracking systems that are managed by, or on behalf of, the -Licensor for the purpose of discussing and improving the Work, but -excluding communication that is conspicuously marked or otherwise -designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity -on behalf of whom a Contribution has been received by Licensor and -subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the -Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -(except as stated in this section) patent license to make, have made, -use, offer to sell, sell, import, and otherwise transfer the Work, -where such license applies only to those patent claims licensable -by such Contributor that are necessarily infringed by their -Contribution(s) alone or by combination of their Contribution(s) -with the Work to which such Contribution(s) was submitted. If You -institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work -or a Contribution incorporated within the Work constitutes direct -or contributory patent infringement, then any patent licenses -granted to You under this License for that Work shall terminate -as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the -Work or Derivative Works thereof in any medium, with or without -modifications, and in Source or Object form, provided that You -meet the following conditions: - -(a) You must give any other recipients of the Work or -Derivative Works a copy of this License; and - -(b) You must cause any modified files to carry prominent notices -stating that You changed the files; and - -(c) You must retain, in the Source form of any Derivative Works -that You distribute, all copyright, patent, trademark, and -attribution notices from the Source form of the Work, -excluding those notices that do not pertain to any part of -the Derivative Works; and - -(d) If the Work includes a "NOTICE" text file as part of its -distribution, then any Derivative Works that You distribute must -include a readable copy of the attribution notices contained -within such NOTICE file, excluding those notices that do not -pertain to any part of the Derivative Works, in at least one -of the following places: within a NOTICE text file distributed -as part of the Derivative Works; within the Source form or -documentation, if provided along with the Derivative Works; or, -within a display generated by the Derivative Works, if and -wherever such third-party notices normally appear. The contents -of the NOTICE file are for informational purposes only and -do not modify the License. You may add Your own attribution -notices within Derivative Works that You distribute, alongside -or as an addendum to the NOTICE text from the Work, provided -that such additional attribution notices cannot be construed -as modifying the License. - -You may add Your own copyright statement to Your modifications and -may provide additional or different license terms and conditions -for use, reproduction, or distribution of Your modifications, or -for any such Derivative Works as a whole, provided Your use, -reproduction, and distribution of the Work otherwise complies with -the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, -any Contribution intentionally submitted for inclusion in the Work -by You to the Licensor shall be under the terms and conditions of -this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify -the terms of any separate license agreement you may have executed -with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade -names, trademarks, service marks, or product names of the Licensor, -except as required for reasonable and customary use in describing the -origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or -agreed to in writing, Licensor provides the Work (and each -Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied, including, without limitation, any warranties or conditions -of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -PARTICULAR PURPOSE. You are solely responsible for determining the -appropriateness of using or redistributing the Work and assume any -risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, -whether in tort (including ne gligence), contract, or otherwise, -unless required by applicable law (such as deliberate and grossly -negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, -incidental, or consequential damages of any character arising as a -result of this License or out of the use or inability to use the -Work (including but not limited to damages for loss of goodwill, -work stoppage, computer failure or malfunction, or any and all -other commercial damages or losses), even if such Contributor -has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing -the Work or Derivative Works thereof, You may choose to offer, -and charge a fee for, acceptance of support, warranty, indemnity, -or other liability obligations and/or rights consistent with this -License. However, in accepting such obligations, You may act only -on Your own behalf and on Your sole responsibility, not on behalf -of any other Contributor, and only if You agree to indemnify, -defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason -of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following -boilerplate notice, with the fields enclosed by brackets "[]" -replaced with your own identifying information. (Don't include -the brackets!) The text should be enclosed in the appropriate -comment syntax for the file format. We also recommend that a -file or class name and description of purpose be included on the -same "printed page" as the copyright notice for easier -identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*************************************************************************** -%%The following software may be included in this product: -Jsch -Use of any of this software is governed by the terms of the license below: -JSch 0.0.* was released under the GNU LGPL license. Later, we have switched -over to a BSD-style license. - ------------------------------------------------------------------------------- -Copyright (c) 2002,2003,2004,2005,2006,2007,2008 Atsuhiko Yamanaka, JCraft,Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. 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. - -3. The names of the authors may not be used to endorse or promote products -derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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. -Additional License(s) -LICENSE.txt:JSch 0.0.* was released under the GNU LGPL license. -Later, we have switched -LICENSE.txt:over to a BSD-style license. -*************************************************************************** -%%The following software may be included in this product: -Expect4j -Use of any of this software is governed by the terms of the license below: -Apache License, Version 2.0 - -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -"submitted" means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this -License, each Contributor hereby grants to You a perpetual, worldwide, -non-exclusive, no-charge, royalty-free, irrevocable copyright license to -reproduce, prepare Derivative Works of, publicly display, publicly perform, -sublicense, and distribute the Work and such Derivative Works in Source or -Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, -each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) patent -license to make, have made, use, offer to sell, sell, import, and otherwise -transfer the Work, where such license applies only to those patent claims -licensable by such Contributor that are necessarily infringed by their -Contribution(s) alone or by combination of their Contribution(s) with the Work -to which such Contribution(s) was submitted. If You institute patent litigation -against any entity (including a cross-claim or counterclaim in a lawsuit) -alleging that the Work or a Contribution incorporated within the Work -constitutes direct or contributory patent infringement, then any patent licenses -granted to You under this License for that Work shall terminate as of the date -such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or -Derivative Works thereof in any medium, with or without modifications, and in -Source or Object form, provided that You meet the following conditions: - -1. You must give any other recipients of the Work or Derivative Works a copy -of this License; and - -2. You must cause any modified files to carry prominent notices stating that -You changed the files; and - -3. You must retain, in the Source form of any Derivative Works that You -distribute, all copyright, patent, trademark, and attribution notices from the -Source form of the Work, excluding those notices that do not pertain to any part -of the Derivative Works; and - -4. If the Work includes a "NOTICE" text file as part of its distribution, -then any Derivative Works that You distribute must include a readable copy of -the attribution notices contained within such NOTICE file, excluding those -notices that do not pertain to any part of the Derivative Works, in at least one -of the following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. - -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -provided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any -Contribution intentionally submitted for inclusion in the Work by You to the -Licensor shall be under the terms and conditions of this License, without any -additional terms or conditions. Notwithstanding the above, nothing herein shall -supersede or modify the terms of any separate license agreement you may have -executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, -trademarks, service marks, or product names of the Licensor, except as required -for reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in -writing, Licensor provides the Work (and each Contributor provides its -Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied, including, without limitation, any warranties -or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -PARTICULAR PURPOSE. You are solely responsible for determining the -appropriateness of using or redistributing the Work and assume any risks -associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in -tort (including negligence), contract, or otherwise, unless required by -applicable law (such as deliberate and grossly negligent acts) or agreed to in -writing, shall any Contributor be liable to You for damages, including any -direct, indirect, special, incidental, or consequential damages of any character -arising as a result of this License or out of the use or inability to use the -Work (including but not limited to damages for loss of goodwill, work stoppage, -computer failure or malfunction, or any and all other commercial damages or -losses), even if such Contributor has been advised of the possibility of such -damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or -Derivative Works thereof, You may choose to offer, and charge a fee for, -acceptance of support, warranty, indemnity, or other liability obligations -and/or rights consistent with this License. However, in accepting such -obligations, You may act only on Your own behalf and on Your sole -responsibility, not on behalf of any other Contributor, and only if You agree to -indemnify, defend, and hold each Contributor harmless for any liability incurred -by, or claims asserted against, such Contributor by reason of your accepting any -such warranty or additional liability. - -END OF TERMS AND CONDITIONS -APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same "printed page" as the copyright notice for easier identification within -third-party archives. -Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, -Version 2.0 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or -agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -or implied. See the License for the specific language governing permissions and -limitations under the License. -Apache Projects - -* HTTP Server -* ActiveMQ -* Ant -* APR -* Archiva -* Beehive -* Cayenne -* Cocoon -* Commons -* Continuum -* CXF -* DB -* Directory -* Excalibur -* Felix -* Forrest -* Geronimo -* Gump -* Hadoop -* Harmony -* HiveMind -* HttpComponents -* iBATIS -* Incubator -* Jackrabbit -* Jakarta -* James -* Labs -* Lenya -* Logging -* Lucene -* Maven -* Mina -* MyFaces -* ODE -* OFBiz -* OpenEJB -* OpenJPA -* Perl -* POI -* Portals -* Roller -* Santuario -* ServiceMix -* Shale -* SpamAssassin -* STDCXX -* Struts -* Synapse -* Tapestry -* TCL -* Tiles -* Tomcat -* Turbine -* Velocity -* Wicket -* Web Services -* Xalan -* Xerces -* XML -* XMLBeans -* XML Graphics - -Foundation - -* FAQ -* Licenses -* News -* Public Records -* Sponsorship -* Donations -* Thanks -* Contact - -Foundation Projects - -* Conferences -* Infrastructure -* JCP - -How it works - -* Introduction -* Meritocracy -* Structure -* Roles -* Collaboration -* Infrastructure -* Incubator -* Other entities -* Glossary -* Voting - -Get Involved - -* Mailing Lists -* Version Control -* Developer Info - -Download - -* from a mirror - -Related Sites - -* ApacheCon -* Bookstore -* Feathercast -* PlanetApache - -Copyright � 2008 The Apache Software Foundation, Licensed under the Apache -License, Version 2.0. -*************************************************************************** -%%The following software may be included in this product: -FreeHost3270 -Use of any of this software is governed by the terms of the license below: -GNU LESSER GENERAL PUBLIC LICENSE - -Version 2.1, February 1999 - -Copyright (C) 1991, 1999 Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts -as the successor of the GNU Library Public License, version 2, hence -the version number 2.1.] -Preamble - -The licenses for most software are designed to take away your freedom to share and change it. By -contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - -This license, the Lesser General Public License, applies to some specially designated software -packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. -You can use it too, but we suggest you first think carefully about whether this license or the ordinary -General Public License is the better strategy to use in any particular case, based on the explanations -below. - -When we speak of free software, we are referring to freedom of use, not price. Our General Public -Licenses are designed to make sure that you have the freedom to distribute copies of free software (and -charge for this service if you wish); that you receive source code or can get it if you want it; that you -can change the software and use pieces of it in new free programs; and that you are informed that you -can do these things. - -To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or -to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if -you distribute copies of the library or if you modify it. - -For example, if you distribute copies of the library, whether gratis or for a fee, you must give the -recipients all the rights that we gave you. You must make sure that they, too, receive or can get the -source code. If you link other code with the library, you must provide complete object files to the -recipients, so that they can relink them with the library after making changes to the library and -recompiling it. And you must show them these terms so they know their rights. - -We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this -license, which gives you legal permission to copy, distribute and/or modify the library. - -To protect each distributor, we want to make it very clear that there is no warranty for the free library. -Also, if the library is modified by someone else and passed on, the recipients should know that what -they have is not the original version, so that the original author's reputation will not be affected by -problems that might be introduced by others. - -Finally, software patents pose a constant threat to the existence of any free program. We wish to make -sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive -license from a patent holder. Therefore, we insist that any patent license obtained for a version of the -library must be consistent with the full freedom of use specified in this license. - -Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. -This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite -different from the ordinary General Public License. We use this license for certain libraries in order to -permit linking those libraries into non-free programs. - -When a program is linked with a library, whether statically or using a shared library, the combination of -the two is legally speaking a combined work, a derivative of the original library. The ordinary General -Public License therefore permits such linking only if the entire combination fits its criteria of freedom. -The Lesser General Public License permits more lax criteria for linking other code with the library. - -We call this license the "Lesser" General Public License because it does Less to protect the user's -freedom than the ordinary General Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages are the reason we use the -ordinary General Public License for many libraries. However, the Lesser license provides advantages in -certain special circumstances. - -For example, on rare occasions, there may be a special need to encourage the widest possible use of a -certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free library does the same job as widely used -non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so -we use the Lesser General Public License. - -In other cases, permission to use a particular library in non-free programs enables a greater number of -people to use a large body of free software. For example, permission to use the GNU C Library in non- -free programs enables many more people to use the whole GNU operating system, as well as its variant, -the GNU/Linux operating system. - -Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that -the user of a program that is linked with the Library has the freedom and the wherewithal to run that -program using a modified version of the Library. - -The precise terms and conditions for copying, distribution and modification follow. Pay close attention -to the difference between a "work based on the library" and a "work that uses the library". The former -contains code derived from the library, whereas the latter must be combined with the library in order to -run. - -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -0. This License Agreement applies to any software library or other program which contains a notice -placed by the copyright holder or other authorized party saying it may be distributed under the terms -of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". - -A "library" means a collection of software functions and/or data prepared so as to be conveniently -linked with application programs (which use some of those functions and data) to form executables. - -The "Library", below, refers to any such software library or work which has been distributed under these -terms. A "work based on the Library" means either the Library or any derivative work under copyright -law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications -and/or translated straightforwardly into another language. (Hereinafter, translation is included without -limitation in the term "modification".) - -"Source code" for a work means the preferred form of the work for making modifications to it. For a -library, complete source code means all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation and installation of the library. - -Activities other than copying, distribution and modification are not covered by this License; they are -outside its scope. The act of running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based on the Library (independent of -the use of the Library in a tool for writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - -1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, -in any medium, provided that you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this -License and to the absence of any warranty; and distribute a copy of this License along with the Library. - -You may charge a fee for the physical act of transferring a copy, and you may at your option offer -warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based -on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, -provided that you also meet all of these conditions: - -a) The modified work must itself be a software library. -b) You must cause the files modified to carry prominent notices stating that you changed the files and -the date of any change. -c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms -of this License. -d) If a facility in the modified Library refers to a function or a table of data to be supplied by an -application program that uses the facility, other than as an argument passed when the facility is -invoked, then you must make a good faith effort to ensure that, in the event an application does not -supply such function or table, the facility still operates, and performs whatever part of its purpose -remains meaningful. -(For example, a function in a library to compute square roots has a purpose that is entirely well- -defined independent of the application. Therefore, Subsection 2d requires that any application- -supplied function or table used by this function must be optional: if the application does not supply it, -the square root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If identifiable sections of that work are not -derived from the Library, and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those sections when you distribute them as -separate works. But when you distribute the same sections as part of a whole which is a work based on -the Library, the distribution of the whole must be on the terms of this License, whose permissions for -other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. -Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by -you; rather, the intent is to exercise the right to control the distribution of derivative or collective works -based on the Library. - -In addition, mere aggregation of another work not based on the Library with the Library (or with a work -based on the Library) on a volume of a storage or distribution medium does not bring the other work -under the scope of this License. - -3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to -a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that -they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer -version than version 2 of the ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in these notices. - -Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General -Public License applies to all subsequent copies and derivative works made from that copy. - -This option is useful when you wish to copy part of the code of the Library into a program that is not a -library. - -4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object -code or executable form under the terms of Sections 1 and 2 above provided that you accompany it -with the complete corresponding machine-readable source code, which must be distributed under the -terms of Sections 1 and 2 above on a medium customarily used for software interchange. - -If distribution of object code is made by offering access to copy from a designated place, then offering -equivalent access to copy the source code from the same place satisfies the requirement to distribute -the source code, even though third parties are not compelled to copy the source along with the object -code. - -5. A program that contains no derivative of any portion of the Library, but is designed to work with the -Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in -isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. - -However, linking a "work that uses the Library" with the Library creates an executable that is a -derivative of the Library (because it contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. Section 6 states terms for distribution of -such executables. - -When a "work that uses the Library" uses material from a header file that is part of the Library, the -object code for the work may be a derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be linked without the Library, or if the work -is itself a library. The threshold for this to be true is not precisely defined by law. - -If such an object file uses only numerical parameters, data structure layouts and accessors, and small -macros and small inline functions (ten lines or less in length), then the use of the object file is -unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object -code plus portions of the Library will still fall under Section 6.) - -Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work -under the terms of Section 6. Any executables containing that work also fall under Section 6, whether -or not they are linked directly with the Library itself. - -6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" -with the Library to produce a work containing portions of the Library, and distribute that work under -terms of your choice, provided that the terms permit modification of the work for the customer's own -use and reverse engineering for debugging such modifications. - -You must give prominent notice with each copy of the work that the Library is used in it and that the -Library and its use are covered by this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the copyright notice for the Library -among them, as well as a reference directing the user to the copy of this License. Also, you must do -one of these things: - -a) Accompany the work with the complete corresponding machine-readable source code for the Library -including whatever changes were used in the work (which must be distributed under Sections 1 and 2 -above); and, if the work is an executable linked with the Library, with the complete machine-readable -"work that uses the Library", as object code and/or source code, so that the user can modify the Library -and then relink to produce a modified executable containing the modified Library. (It is understood that -the user who changes the contents of definitions files in the Library will not necessarily be able to -recompile the application to use the modified definitions.) -b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one -that (1) uses at run time a copy of the library already present on the user's computer system, rather -than copying library functions into the executable, and (2) will operate properly with a modified version -of the library, if the user installs one, as long as the modified version is interface-compatible with the -version that the work was made with. -c) Accompany the work with a written offer, valid for at least three years, to give the same user the -materials specified in Subsection 6a, above, for a charge no more than the cost of performing this -distribution. -d) If distribution of the work is made by offering access to copy from a designated place, offer -equivalent access to copy the above specified materials from the same place. -e) Verify that the user has already received a copy of these materials or that you have already sent this -user a copy. -For an executable, the required form of the "work that uses the Library" must include any data and -utility programs needed for reproducing the executable from it. However, as a special exception, the -materials to be distributed need not include anything that is normally distributed (in either source or -binary form) with the major components (compiler, kernel, and so on) of the operating system on which -the executable runs, unless that component itself accompanies the executable. - -It may happen that this requirement contradicts the license restrictions of other proprietary libraries -that do not normally accompany the operating system. Such a contradiction means you cannot use both -them and the Library together in an executable that you distribute. - -7. You may place library facilities that are a work based on the Library side-by-side in a single library -together with other library facilities not covered by this License, and distribute such a combined library, -provided that the separate distribution of the work based on the Library and of the other library -facilities is otherwise permitted, and provided that you do these two things: - -a) Accompany the combined library with a copy of the same work based on the Library, uncombined -with any other library facilities. This must be distributed under the terms of the Sections above. -b) Give prominent notice with the combined library of the fact that part of it is a work based on the -Library, and explaining where to find the accompanying uncombined form of the same work. -8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly -provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute -the Library is void, and will automatically terminate your rights under this License. However, parties -who have received copies, or rights, from you under this License will not have their licenses terminated -so long as such parties remain in full compliance. - -9. You are not required to accept this License, since you have not signed it. However, nothing else -grants you permission to modify or distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library -(or any work based on the Library), you indicate your acceptance of this License to do so, and all its -terms and conditions for copying, distributing or modifying the Library or works based on it. - -10. Each time you redistribute the Library (or any work based on the Library), the recipient -automatically receives a license from the original licensor to copy, distribute, link with or modify the -Library subject to these terms and conditions. You may not impose any further restrictions on the -recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by -third parties with this License. - -11. If, as a consequence of a court judgment or allegation of patent infringement or for any other -reason (not limited to patent issues), conditions are imposed on you (whether by court order, -agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the -conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations -under this License and any other pertinent obligations, then as a consequence you may not distribute -the Library at all. For example, if a patent license would not permit royalty-free redistribution of the -Library by all those who receive copies directly or indirectly through you, then the only way you could -satisfy both it and this License would be to refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any particular circumstance, the -balance of the section is intended to apply, and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any patents or other property right claims -or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of -the free software distribution system which is implemented by public license practices. Many people -have made generous contributions to the wide range of software distributed through that system in -reliance on consistent application of that system; it is up to the author/donor to decide if he or she is -willing to distribute software through any other system and a licensee cannot impose that choice. - -This section is intended to make thoroughly clear what is believed to be a consequence of the rest of -this License. - -12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by -copyrighted interfaces, the original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, so that distribution is -permitted only in or among countries not thus excluded. In such case, this License incorporates the -limitation as if written in the body of this License. - -13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public -License from time to time. Such new versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library specifies a version number of this -License which applies to it and "any later version", you have the option of following the terms and -conditions either of that version or of any later version published by the Free Software Foundation. If -the Library does not specify a license version number, you may choose any version ever published by -the Free Software Foundation. - -14. If you wish to incorporate parts of the Library into other free programs whose distribution -conditions are incompatible with these, write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals of preserving the free status of -all derivatives of our free software and of promoting the sharing and reuse of software generally. - -NO WARRANTY - -15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, -TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE -COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF -ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY -AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU -ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY -COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS -PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL -OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY -(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES -SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER -SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Libraries - -If you develop a new library, and you want it to be of the greatest possible use to the public, we -recommend making it free software that everyone can redistribute and change. You can do so by -permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General -Public License). - -To apply these terms, attach the following notices to the library. It is safest to attach them to the start -of each source file to most effectively convey the exclusion of warranty; and each file should have at -least the "copyright" line and a pointer to where the full notice is found. - -one line to give the library's name and an idea of what it does. -Copyright (C) year name of author - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your school, if any, to sign a -"copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: - -Yoyodyne, Inc., hereby disclaims all copyright interest in -the library `Frob' (a library for tweaking knobs) written -by James Random Hacker. - -signature of Ty Coon, 1 April 1990 -Ty Coon, President of Vice -That's all there is to it! -*************************************************************************** -%%The following software may be included in this product: -Boo -Use of any of this software is governed by the terms of the license below: -Copyright (c) 2003, 2004, Rodrigo B. de Oliveira (rbo@acm.org) -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 Rodrigo B. de Oliveira 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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. -*************************************************************************** - diff --git a/legal-notices/CDDLv1_0.txt b/legal-notices/CDDLv1_0.txt new file mode 100644 index 0000000..da23621 --- /dev/null +++ b/legal-notices/CDDLv1_0.txt @@ -0,0 +1,384 @@ +Unless otherwise noted, all files in this distribution are released +under the Common Development and Distribution License (CDDL). +Exceptions are noted within the associated source files. + +-------------------------------------------------------------------- + + +COMMON DEVELOPMENT AND DISTRIBUTION LICENSE Version 1.0 + +1. Definitions. + + 1.1. "Contributor" means each individual or entity that creates + or contributes to the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Software, prior Modifications used by a Contributor (if any), + and the Modifications made by that particular Contributor. + + 1.3. "Covered Software" means (a) the Original Software, or (b) + Modifications, or (c) the combination of files containing + Original Software with files containing Modifications, in + each case including portions thereof. + + 1.4. "Executable" means the Covered Software in any form other + than Source Code. + + 1.5. "Initial Developer" means the individual or entity that first + makes Original Software available under this License. + + 1.6. "Larger Work" means a work which combines Covered Software or + portions thereof with code not governed by the terms of this + License. + + 1.7. "License" means this document. + + 1.8. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed + herein. + + 1.9. "Modifications" means the Source Code and Executable form of + any of the following: + + A. Any file that results from an addition to, deletion from or + modification of the contents of a file containing Original + Software or previous Modifications; + + B. Any new file that contains any part of the Original + Software or previous Modifications; or + + C. Any new file that is contributed or otherwise made + available under the terms of this License. + + 1.10. "Original Software" means the Source Code and Executable + form of computer software code that is originally released + under this License. + + 1.11. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, + process, and apparatus claims, in any patent Licensable by + grantor. + + 1.12. "Source Code" means (a) the common form of computer software + code in which modifications are made and (b) associated + documentation included in or with such code. + + 1.13. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms + of, this License. For legal entities, "You" includes any + entity which controls, is controlled by, or is under common + control with You. For purposes of this definition, + "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of more than fifty + percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants. + + 2.1. The Initial Developer Grant. + + Conditioned upon Your compliance with Section 3.1 below and + subject to third party intellectual property claims, the Initial + Developer hereby grants You a world-wide, royalty-free, + non-exclusive license: + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer, to use, + reproduce, modify, display, perform, sublicense and + distribute the Original Software (or portions thereof), + with or without Modifications, and/or as part of a Larger + Work; and + + (b) under Patent Claims infringed by the making, using or + selling of Original Software, to make, have made, use, + practice, sell, and offer for sale, and/or otherwise + dispose of the Original Software (or portions thereof). + + (c) The licenses granted in Sections 2.1(a) and (b) are + effective on the date Initial Developer first distributes + or otherwise makes the Original Software available to a + third party under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: (1) for code that You delete from the Original + Software, or (2) for infringements caused by: (i) the + modification of the Original Software, or (ii) the + combination of the Original Software with other software + or devices. + + 2.2. Contributor Grant. + + Conditioned upon Your compliance with Section 3.1 below and + subject to third party intellectual property claims, each + Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor to use, reproduce, + modify, display, perform, sublicense and distribute the + Modifications created by such Contributor (or portions + thereof), either on an unmodified basis, with other + Modifications, as Covered Software and/or as part of a + Larger Work; and + + (b) under Patent Claims infringed by the making, using, or + selling of Modifications made by that Contributor either + alone and/or in combination with its Contributor Version + (or portions of such combination), to make, use, sell, + offer for sale, have made, and/or otherwise dispose of: + (1) Modifications made by that Contributor (or portions + thereof); and (2) the combination of Modifications made by + that Contributor with its Contributor Version (or portions + of such combination). + + (c) The licenses granted in Sections 2.2(a) and 2.2(b) are + effective on the date Contributor first distributes or + otherwise makes the Modifications available to a third + party. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: (1) for any code that Contributor has deleted + from the Contributor Version; (2) for infringements caused + by: (i) third party modifications of Contributor Version, + or (ii) the combination of Modifications made by that + Contributor with other software (except as part of the + Contributor Version) or other devices; or (3) under Patent + Claims infringed by Covered Software in the absence of + Modifications made by that Contributor. + +3. Distribution Obligations. + + 3.1. Availability of Source Code. + + Any Covered Software that You distribute or otherwise make + available in Executable form must also be made available in Source + Code form and that Source Code form must be distributed only under + the terms of this License. You must include a copy of this + License with every copy of the Source Code form of the Covered + Software You distribute or otherwise make available. You must + inform recipients of any such Covered Software in Executable form + as to how they can obtain such Covered Software in Source Code + form in a reasonable manner on or through a medium customarily + used for software exchange. + + 3.2. Modifications. + + The Modifications that You create or to which You contribute are + governed by the terms of this License. You represent that You + believe Your Modifications are Your original creation(s) and/or + You have sufficient rights to grant the rights conveyed by this + License. + + 3.3. Required Notices. + + You must include a notice in each of Your Modifications that + identifies You as the Contributor of the Modification. You may + not remove or alter any copyright, patent or trademark notices + contained within the Covered Software, or any notices of licensing + or any descriptive text giving attribution to any Contributor or + the Initial Developer. + + 3.4. Application of Additional Terms. + + You may not offer or impose any terms on any Covered Software in + Source Code form that alters or restricts the applicable version + of this License or the recipients' rights hereunder. You may + choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of + Covered Software. However, you may do so only on Your own behalf, + and not on behalf of the Initial Developer or any Contributor. + You must make it absolutely clear that any such warranty, support, + indemnity or liability obligation is offered by You alone, and You + hereby agree to indemnify the Initial Developer and every + Contributor for any liability incurred by the Initial Developer or + such Contributor as a result of warranty, support, indemnity or + liability terms You offer. + + 3.5. Distribution of Executable Versions. + + You may distribute the Executable form of the Covered Software + under the terms of this License or under the terms of a license of + Your choice, which may contain terms different from this License, + provided that You are in compliance with the terms of this License + and that the license for the Executable form does not attempt to + limit or alter the recipient's rights in the Source Code form from + the rights set forth in this License. If You distribute the + Covered Software in Executable form under a different license, You + must make it absolutely clear that any terms which differ from + this License are offered by You alone, not by the Initial + Developer or Contributor. You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred + by the Initial Developer or such Contributor as a result of any + such terms You offer. + + 3.6. Larger Works. + + You may create a Larger Work by combining Covered Software with + other code not governed by the terms of this License and + distribute the Larger Work as a single product. In such a case, + You must make sure the requirements of this License are fulfilled + for the Covered Software. + +4. Versions of the License. + + 4.1. New Versions. + + Sun Microsystems, Inc. is the initial license steward and may + publish revised and/or new versions of this License from time to + time. Each version will be given a distinguishing version number. + Except as provided in Section 4.3, no one other than the license + steward has the right to modify this License. + + 4.2. Effect of New Versions. + + You may always continue to use, distribute or otherwise make the + Covered Software available under the terms of the version of the + License under which You originally received the Covered Software. + If the Initial Developer includes a notice in the Original + Software prohibiting it from being distributed or otherwise made + available under any subsequent version of the License, You must + distribute and make the Covered Software available under the terms + of the version of the License under which You originally received + the Covered Software. Otherwise, You may also choose to use, + distribute or otherwise make the Covered Software available under + the terms of any subsequent version of the License published by + the license steward. + + 4.3. Modified Versions. + + When You are an Initial Developer and You want to create a new + license for Your Original Software, You may create and use a + modified version of this License if You: (a) rename the license + and remove any references to the name of the license steward + (except to note that the license differs from this License); and + (b) otherwise make it clear that the license contains terms which + differ from this License. + +5. DISCLAIMER OF WARRANTY. + + COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" + BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, + INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED + SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR + PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND + PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY + COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE + INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY + NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF + WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF + ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS + DISCLAIMER. + +6. TERMINATION. + + 6.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to + cure such breach within 30 days of becoming aware of the breach. + Provisions which, by their nature, must remain in effect beyond + the termination of this License shall survive. + + 6.2. If You assert a patent infringement claim (excluding + declaratory judgment actions) against Initial Developer or a + Contributor (the Initial Developer or Contributor against whom You + assert such claim is referred to as "Participant") alleging that + the Participant Software (meaning the Contributor Version where + the Participant is a Contributor or the Original Software where + the Participant is the Initial Developer) directly or indirectly + infringes any patent, then any and all rights granted directly or + indirectly to You by such Participant, the Initial Developer (if + the Initial Developer is not the Participant) and all Contributors + under Sections 2.1 and/or 2.2 of this License shall, upon 60 days + notice from Participant terminate prospectively and automatically + at the expiration of such 60 day notice period, unless if within + such 60 day period You withdraw Your claim with respect to the + Participant Software against such Participant either unilaterally + or pursuant to a written agreement with Participant. + + 6.3. In the event of termination under Sections 6.1 or 6.2 above, + all end user licenses that have been validly granted by You or any + distributor hereunder prior to termination (excluding licenses + granted to You by any distributor) shall survive termination. + +7. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE + INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF + COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE + LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR + CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT + LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK + STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL + INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT + APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO + NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR + CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT + APPLY TO YOU. + +8. U.S. GOVERNMENT END USERS. + + The Covered Software is a "commercial item," as that term is + defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial + computer software" (as that term is defined at 48 + C.F.R. 252.227-7014(a)(1)) and "commercial computer software + documentation" as such terms are used in 48 C.F.R. 12.212 + (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 + C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all + U.S. Government End Users acquire Covered Software with only those + rights set forth herein. This U.S. Government Rights clause is in + lieu of, and supersedes, any other FAR, DFAR, or other clause or + provision that addresses Government rights in computer software + under this License. + +9. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed + by the law of the jurisdiction specified in a notice contained + within the Original Software (except to the extent applicable law, + if any, provides otherwise), excluding such jurisdiction's + conflict-of-law provisions. Any litigation relating to this + License shall be subject to the jurisdiction of the courts located + in the jurisdiction and venue specified in a notice contained + within the Original Software, with the losing party responsible + for costs, including, without limitation, court costs and + reasonable attorneys' fees and expenses. The application of the + United Nations Convention on Contracts for the International Sale + of Goods is expressly excluded. Any law or regulation which + provides that the language of a contract shall be construed + against the drafter shall not apply to this License. You agree + that You alone are responsible for compliance with the United + States export administration regulations (and the export control + laws and regulation of any other countries) when You use, + distribute or otherwise make available any Covered Software. + +10. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or + indirectly, out of its utilization of rights under this License + and You agree to work with Initial Developer and Contributors to + distribute such responsibility on an equitable basis. Nothing + herein is intended or shall be deemed to constitute any admission + of liability. + +-------------------------------------------------------------------- + +NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND +DISTRIBUTION LICENSE (CDDL) + +For Covered Software in this distribution, this License shall +be governed by the laws of the State of California (excluding +conflict-of-law provisions). + +Any litigation relating to this License shall be subject to the +jurisdiction of the Federal Courts of the Northern District of +California and the state courts of the State of California, with +venue lying in Santa Clara County, California. diff --git a/legal-notices/ForgeRock_License.txt b/legal-notices/ForgeRock_License.txt new file mode 100644 index 0000000..748cd37 --- /dev/null +++ b/legal-notices/ForgeRock_License.txt @@ -0,0 +1,144 @@ +READ THIS SOFTWARE LICENSE AGREEMENT CAREFULLY. BY DOWNLOADING OR INSTALLING +THE FORGEROCK SOFTWARE, YOU, ON BEHALF OF YOURSELF AND YOUR COMPANY, AGREE TO +BE BOUND BY THIS SOFTWARE LICENSE AGREEMENT. IF YOU DO NOT AGREE TO THESE +TERMS, DO NOT DOWNLOAD OR INSTALL THE FORGEROCK SOFTWARE. + +1. Software License. + +1.1. Development Right to Use. If Company intends to or does use the ForgeRock +Software only for the purpose(s) of developing, testing, prototyping and +demonstrating its application software, then ForgeRock hereby grants Company a +nonexclusive, nontransferable, limited license to use the ForgeRock Software +only for those purposes, solely at Company's facilities and only in a +non-production environment. ForgeRock may audit Company's use of the ForgeRock +Software to confirm that a production license is not required upon reasonable +written notice to Company. If Company intends to use the ForgeRock Software in +a live environment, Company must purchase a production license and may only use +the ForgeRock Software licensed thereunder in accordance with the terms and +conditions of that subscription agreement. + +1.2. Restrictions. Except as expressly set forth in this ForgeRock Software +License Agreement (the "Agreement"), Company shall not, directly or indirectly: +(a) sublicense, resell, rent, lease, distribute or otherwise transfer rights or +usage in the ForgeRock Software, including without limitation to Company +subsidiaries and affiliates; (b) remove or alter any copyright, trademark or +proprietary notices in the ForgeRock Software; or (c) use the ForgeRock +Software in any way that would subject the ForgeRock Software, in whole in or +in part, to a Copyleft License. As used herein, "Copyleft License" means a +software license that requires that information necessary for reproducing and +modifying such software must be made available publicly to recipients of +executable versions of such software (see, e.g., GNU General Public License and +http://www.gnu.org/copyleft/). + +2. Proprietary Rights. + +2.1. ForgeRock Intellectual Property. Title to and ownership of all copies of +the ForgeRock Software whether in machine-readable (source, object code or +other format) or printed form, and all related technical know-how and all +rights therein (including without limitation all intellectual property rights +applicable thereto), belong to ForgeRock and its licensors and shall remain the +exclusive property thereof. ForgeRock's name, logo, trade names and trademarks +are owned exclusively by ForgeRock and no right is granted to Company to use +any of the foregoing except as expressly permitted herein. All rights not +expressly granted to Company are reserved by ForgeRock and its licensors. + +2.2. Suggestions. Company hereby grants to ForgeRock a royalty-free, worldwide, +transferable, sublicensable and irrevocable right and license to use, copy, +modify and distribute, including by incorporating into any product or service +owned by ForgeRock, any suggestions, enhancements, recommendations or other +feedback provided by Company relating to any product or service owned or +offered by ForgeRock. + +2.3. Source Code. The source code underlying the ForgeRock Software is +available at www.forgerock.org. + +3. Term and Termination. The terms of this Agreement shall commence on the +Effective Date and shall continue in force unless earlier terminated in +accordance this Section. This Agreement shall terminate without notice to +Company in the event Company is in material breach of any of the terms and +conditions of this Agreement. As used herein, "Effective Date" means the date +on which Company first accepted this Agreement and downloads the ForgeRock +Software. + +4. Disclaimer of Warranties. THE FORGEROCK SOFTWARE LICENSED HEREUNDER IS +LICENSED "AS IS" AND WITHOUT WARRANTY OF ANY KIND. FORGEROCK AND IT'S LICENSORS +EXPRESSLY DISCLAIM ALL WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, +INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND ANY WARRANTY OF NON-INFRINGEMENT. + +5. General Indemnification. Company shall defend, indemnify and hold ForgeRock +harmless from and against any and all liabilities, damages, losses, costs and +expenses (including but not limited to reasonable fees of attorneys and other +professionals) payable to third parties based upon any claim arising out of or +related to the use of Company's products, provided that ForgeRock: (a) promptly +notifies Company of the claim; (b) provides Company with all reasonable +information and assistance, at Company's expense, to defend or settle such a +claim; and (c) grants Company authority and control of the defense or +settlement of such claim. Company shall not settle any such claim, without +ForgeRock's prior written consent, if such settlement would in any manner +effect ForgeRock's rights in the ForgeRock Software or otherwise. ForgeRock +reserves the right to retain counsel, at ForgeRock's expense, to participate in +the defense and settlement of any such claim. + +6. Limitation of Liability. IN NO EVENT SHALL FORGEROCK BE LIABLE FOR THE COST +OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, ANY LOST PROFITS, REVENUE, OR +DATA, INTERRUPTION OF BUSINESS OR FOR ANY INCIDENTAL, SPECIAL, CONSEQUENTIAL OR +INDIRECT DAMAGES OF ANY KIND, AND WHETHER ARISING OUT OF BREACH OF WARRANTY, +BREACH OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE OR IF SUCH DAMAGE COULD HAVE +BEEN REASONABLY FORESEEN. IN NO EVENT SHALL FORGEROCK'S LIABILITY ARISING OUT +OF OR RELATED TO THIS AGREEMENT WHETHER IN CONTRACT, TORT OR UNDER ANY OTHER +THEORY OF LIABILITY, EXCEED IN THE AGGREGATE $1,000 USD. + +7. General. + +7.1. Governing Law. This Agreement shall be governed by and interpreted in +accordance with the laws of the State of California without reference to its +conflicts of law provisions. + +7.2. Assignment. Company may not assign any of its rights or obligations under +this Agreement without the prior written consent of ForgeRock, which consent +shall not be unreasonably withheld. Any assignment not in conformity with this +Section shall be null and void. + +7.3. Waiver. A waiver on one occasion shall not be construed as a waiver of any +right on any future occasion. No delay or omission by a party in exercising any +of its rights hereunder shall operate as a waiver of such rights. + +7.4. Compliance with Law. The ForgeRock Software is subject to U.S. export +control laws, including the U.S. Export Administration Act and its associated +regulations, and may be subject to export or import regulations in other +countries. Company agrees to comply with all laws and regulations of the United +States and other countries ("Export Laws") to assure that neither the ForgeRock +Software, nor any direct products thereof are; (a) exported, directly or +indirectly, in violation of Export Laws, either to any countries that are +subject to U.S. export restrictions or to any end user who has been prohibited +from participating in the U.S. export transactions by any federal agency of the +U.S. government or (b) intended to be used for any purpose prohibited by Export +Laws, including, without limitation, nuclear, chemical, or biological weapons +proliferation. + +7.5. US Government Restrictions. Company acknowledges that the ForgeRock +Software consists of "commercial computer software" and "commercial computer +software documentation" as such terms are defined in the Code of Federal +Regulations. No Government procurement regulations or contract clauses or +provisions shall be deemed a part of any transaction between the parties unless +its inclusion is required by law, or mutually agreed in writing by the parties +in connection with a specific transaction. Use, duplication, reproduction, +release, modification, disclosure or transfer of the ForgeRock Software is +restricted in accordance with the terms of this Agreement. + +7.6. Provision Severability. In the event that it is determined by a court of +competent jurisdiction that any provision of this Agreement is invalid, +illegal, or otherwise unenforceable, such provision shall be enforced as nearly +as possible in accordance with the stated intention of the parties, while the +remainder of this Agreement shall remain in full force and effect and bind the +parties according to its terms. To the extent any provision cannot be enforced +in accordance with the stated intentions of the parties, such terms and +conditions shall be deemed not to be a part of this Agreement. + +7.7. Entire Agreement. This Agreement constitutes the entire and exclusive +agreement between the parties with respect to the subject matter hereof and +supersede any prior agreements between the parties with respect to such subject +matter + diff --git a/license.txt b/license.txt deleted file mode 100644 index 1717cf2..0000000 --- a/license.txt +++ /dev/null @@ -1,383 +0,0 @@ - - -COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 - -1. Definitions. - -1.1. "Contributor" means each individual or entity that -creates or contributes to the creation of Modifications. - -1.2. "Contributor Version" means the combination of the -Original Software, prior Modifications used by a -Contributor (if any), and the Modifications made by that -particular Contributor. - -1.3. "Covered Software" means (a) the Original Software, or -(b) Modifications, or (c) the combination of files -containing Original Software with files containing -Modifications, in each case including portions thereof. - -1.4. "Executable" means the Covered Software in any form -other than Source Code. - -1.5. "Initial Developer" means the individual or entity -that first makes Original Software available under this -License. - -1.6. "Larger Work" means a work which combines Covered -Software or portions thereof with code not governed by the -terms of this License. - -1.7. "License" means this document. - -1.8. "Licensable" means having the right to grant, to the -maximum extent possible, whether at the time of the initial -grant or subsequently acquired, any and all of the rights -conveyed herein. - -1.9. "Modifications" means the Source Code and Executable -form of any of the following: - -A. Any file that results from an addition to, -deletion from or modification of the contents of a -file containing Original Software or previous -Modifications; - -B. Any new file that contains any part of the -Original Software or previous Modification; or - -C. Any new file that is contributed or otherwise made -available under the terms of this License. - -1.10. "Original Software" means the Source Code and -Executable form of computer software code that is -originally released under this License. - -1.11. "Patent Claims" means any patent claim(s), now owned -or hereafter acquired, including without limitation, -method, process, and apparatus claims, in any patent -Licensable by grantor. - -1.12. "Source Code" means (a) the common form of computer -software code in which modifications are made and (b) -associated documentation included in or with such code. - -1.13. "You" (or "Your") means an individual or a legal -entity exercising rights under, and complying with all of -the terms of, this License. For legal entities, "You" -includes any entity which controls, is controlled by, or is -under common control with You. For purposes of this -definition, "control" means (a) the power, direct or -indirect, to cause the direction or management of such -entity, whether by contract or otherwise, or (b) ownership -of more than fifty percent (50%) of the outstanding shares -or beneficial ownership of such entity. - -2. License Grants. - -2.1. The Initial Developer Grant. - -Conditioned upon Your compliance with Section 3.1 below and -subject to third party intellectual property claims, the -Initial Developer hereby grants You a world-wide, -royalty-free, non-exclusive license: - -(a) under intellectual property rights (other than -patent or trademark) Licensable by Initial Developer, -to use, reproduce, modify, display, perform, -sublicense and distribute the Original Software (or -portions thereof), with or without Modifications, -and/or as part of a Larger Work; and - -(b) under Patent Claims infringed by the making, -using or selling of Original Software, to make, have -made, use, practice, sell, and offer for sale, and/or -otherwise dispose of the Original Software (or -portions thereof). - -(c) The licenses granted in Sections 2.1(a) and (b) -are effective on the date Initial Developer first -distributes or otherwise makes the Original Software -available to a third party under the terms of this -License. - -(d) Notwithstanding Section 2.1(b) above, no patent -license is granted: (1) for code that You delete from -the Original Software, or (2) for infringements -caused by: (i) the modification of the Original -Software, or (ii) the combination of the Original -Software with other software or devices. - -2.2. Contributor Grant. - -Conditioned upon Your compliance with Section 3.1 below and -subject to third party intellectual property claims, each -Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than -patent or trademark) Licensable by Contributor to -use, reproduce, modify, display, perform, sublicense -and distribute the Modifications created by such -Contributor (or portions thereof), either on an -unmodified basis, with other Modifications, as -Covered Software and/or as part of a Larger Work; and - -(b) under Patent Claims infringed by the making, -using, or selling of Modifications made by that -Contributor either alone and/or in combination with -its Contributor Version (or portions of such -combination), to make, use, sell, offer for sale, -have made, and/or otherwise dispose of: (1) -Modifications made by that Contributor (or portions -thereof); and (2) the combination of Modifications -made by that Contributor with its Contributor Version -(or portions of such combination). - -(c) The licenses granted in Sections 2.2(a) and -2.2(b) are effective on the date Contributor first -distributes or otherwise makes the Modifications -available to a third party. - -(d) Notwithstanding Section 2.2(b) above, no patent -license is granted: (1) for any code that Contributor -has deleted from the Contributor Version; (2) for -infringements caused by: (i) third party -modifications of Contributor Version, or (ii) the -combination of Modifications made by that Contributor -with other software (except as part of the -Contributor Version) or other devices; or (3) under -Patent Claims infringed by Covered Software in the -absence of Modifications made by that Contributor. - -3. Distribution Obligations. - -3.1. Availability of Source Code. - -Any Covered Software that You distribute or otherwise make -available in Executable form must also be made available in -Source Code form and that Source Code form must be -distributed only under the terms of this License. You must -include a copy of this License with every copy of the -Source Code form of the Covered Software You distribute or -otherwise make available. You must inform recipients of any -such Covered Software in Executable form as to how they can -obtain such Covered Software in Source Code form in a -reasonable manner on or through a medium customarily used -for software exchange. - -3.2. Modifications. - -The Modifications that You create or to which You -contribute are governed by the terms of this License. You -represent that You believe Your Modifications are Your -original creation(s) and/or You have sufficient rights to -grant the rights conveyed by this License. - -3.3. Required Notices. - -You must include a notice in each of Your Modifications -that identifies You as the Contributor of the Modification. -You may not remove or alter any copyright, patent or -trademark notices contained within the Covered Software, or -any notices of licensing or any descriptive text giving -attribution to any Contributor or the Initial Developer. - -3.4. Application of Additional Terms. - -You may not offer or impose any terms on any Covered -Software in Source Code form that alters or restricts the -applicable version of this License or the recipients' -rights hereunder. You may choose to offer, and to charge a -fee for, warranty, support, indemnity or liability -obligations to one or more recipients of Covered Software. -However, you may do so only on Your own behalf, and not on -behalf of the Initial Developer or any Contributor. You -must make it absolutely clear that any such warranty, -support, indemnity or liability obligation is offered by -You alone, and You hereby agree to indemnify the Initial -Developer and every Contributor for any liability incurred -by the Initial Developer or such Contributor as a result of -warranty, support, indemnity or liability terms You offer. - -3.5. Distribution of Executable Versions. - -You may distribute the Executable form of the Covered -Software under the terms of this License or under the terms -of a license of Your choice, which may contain terms -different from this License, provided that You are in -compliance with the terms of this License and that the -license for the Executable form does not attempt to limit -or alter the recipient's rights in the Source Code form -from the rights set forth in this License. If You -distribute the Covered Software in Executable form under a -different license, You must make it absolutely clear that -any terms which differ from this License are offered by You -alone, not by the Initial Developer or Contributor. You -hereby agree to indemnify the Initial Developer and every -Contributor for any liability incurred by the Initial -Developer or such Contributor as a result of any such terms -You offer. - -3.6. Larger Works. - -You may create a Larger Work by combining Covered Software -with other code not governed by the terms of this License -and distribute the Larger Work as a single product. In such -a case, You must make sure the requirements of this License -are fulfilled for the Covered Software. - -4. Versions of the License. - -4.1. New Versions. - -Sun Microsystems, Inc. is the initial license steward and -may publish revised and/or new versions of this License -from time to time. Each version will be given a -distinguishing version number. Except as provided in -Section 4.3, no one other than the license steward has the -right to modify this License. - -4.2. Effect of New Versions. - -You may always continue to use, distribute or otherwise -make the Covered Software available under the terms of the -version of the License under which You originally received -the Covered Software. If the Initial Developer includes a -notice in the Original Software prohibiting it from being -distributed or otherwise made available under any -subsequent version of the License, You must distribute and -make the Covered Software available under the terms of the -version of the License under which You originally received -the Covered Software. Otherwise, You may also choose to -use, distribute or otherwise make the Covered Software -available under the terms of any subsequent version of the -License published by the license steward. - -4.3. Modified Versions. - -When You are an Initial Developer and You want to create a -new license for Your Original Software, You may create and -use a modified version of this License if You: (a) rename -the license and remove any references to the name of the -license steward (except to note that the license differs -from this License); and (b) otherwise make it clear that -the license contains terms which differ from this License. - -5. DISCLAIMER OF WARRANTY. - -COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" -BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, -INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED -SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR -PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND -PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY -COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE -INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF -ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF -WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF -ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS -DISCLAIMER. - -6. TERMINATION. - -6.1. This License and the rights granted hereunder will -terminate automatically if You fail to comply with terms -herein and fail to cure such breach within 30 days of -becoming aware of the breach. Provisions which, by their -nature, must remain in effect beyond the termination of -this License shall survive. - -6.2. If You assert a patent infringement claim (excluding -declaratory judgment actions) against Initial Developer or -a Contributor (the Initial Developer or Contributor against -whom You assert such claim is referred to as "Participant") -alleging that the Participant Software (meaning the -Contributor Version where the Participant is a Contributor -or the Original Software where the Participant is the -Initial Developer) directly or indirectly infringes any -patent, then any and all rights granted directly or -indirectly to You by such Participant, the Initial -Developer (if the Initial Developer is not the Participant) -and all Contributors under Sections 2.1 and/or 2.2 of this -License shall, upon 60 days notice from Participant -terminate prospectively and automatically at the expiration -of such 60 day notice period, unless if within such 60 day -period You withdraw Your claim with respect to the -Participant Software against such Participant either -unilaterally or pursuant to a written agreement with -Participant. - -6.3. In the event of termination under Sections 6.1 or 6.2 -above, all end user licenses that have been validly granted -by You or any distributor hereunder prior to termination -(excluding licenses granted to You by any distributor) -shall survive termination. - -7. LIMITATION OF LIABILITY. - -UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT -(INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE -INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF -COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE -LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR -CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT -LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK -STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER -COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN -INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF -LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL -INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT -APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO -NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR -CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT -APPLY TO YOU. - -8. U.S. GOVERNMENT END USERS. - -The Covered Software is a "commercial item," as that term is -defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial -computer software" (as that term is defined at 48 C.F.R. $ -252.227-7014(a)(1)) and "commercial computer software -documentation" as such terms are used in 48 C.F.R. 12.212 (Sept. -1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 -through 227.7202-4 (June 1995), all U.S. Government End Users -acquire Covered Software with only those rights set forth herein. -This U.S. Government Rights clause is in lieu of, and supersedes, -any other FAR, DFAR, or other clause or provision that addresses -Government rights in computer software under this License. - -9. MISCELLANEOUS. - -This License represents the complete agreement concerning subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the -extent necessary to make it enforceable. This License shall be -governed by the law of the jurisdiction specified in a notice -contained within the Original Software (except to the extent -applicable law, if any, provides otherwise), excluding such -jurisdiction's conflict-of-law provisions. Any litigation -relating to this License shall be subject to the jurisdiction of -the courts located in the jurisdiction and venue specified in a -notice contained within the Original Software, with the losing -party responsible for costs, including, without limitation, court -costs and reasonable attorneys' fees and expenses. The -application of the United Nations Convention on Contracts for the -International Sale of Goods is expressly excluded. Any law or -regulation which provides that the language of a contract shall -be construed against the drafter shall not apply to this License. -You agree that You alone are responsible for compliance with the -United States export administration regulations (and the export -control laws and regulation of any other countries) when You use, -distribute or otherwise make available any Covered Software. - -10. RESPONSIBILITY FOR CLAIMS. - -As between Initial Developer and the Contributors, each party is -responsible for claims and damages arising, directly or -indirectly, out of its utilization of rights under this License -and You agree to work with Initial Developer and Contributors to -distribute such responsibility on an equitable basis. Nothing -herein is intended or shall be deemed to constitute any admission -of liability. - From 8773c9ea2f4fcd06975cc39ec6f774e82290b096 Mon Sep 17 00:00:00 2001 From: Chris Drake Date: Mon, 27 Oct 2014 14:28:23 +0000 Subject: [PATCH 31/33] OPENICF-129 OPENICF-314 FR-446 Allow updates to the sAMAccountName and userPrincipleName attributes via the .NET Connector --- ActiveDirectoryConnector/ObjectClasses.xml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ActiveDirectoryConnector/ObjectClasses.xml b/ActiveDirectoryConnector/ObjectClasses.xml index 8d1a3c2..61ee554 100644 --- a/ActiveDirectoryConnector/ObjectClasses.xml +++ b/ActiveDirectoryConnector/ObjectClasses.xml @@ -41,12 +41,8 @@ - - - - - - + + From e19aef67fef1704076f78bba073f0c1007c1c2b6 Mon Sep 17 00:00:00 2001 From: Chris Drake Date: Tue, 28 Oct 2014 18:17:43 +0000 Subject: [PATCH 32/33] OPENICF-88 CR-5045 Fix OverflowException thrown when setting __PASSWORD_EXPIRED__==false via AD Connector. --- ActiveDirectoryConnector/ActiveDirectoryUtils.cs | 2 +- .../CustomAttributeHandlers.cs | 14 +------------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/ActiveDirectoryConnector/ActiveDirectoryUtils.cs b/ActiveDirectoryConnector/ActiveDirectoryUtils.cs index 0bb9826..edb2fc9 100644 --- a/ActiveDirectoryConnector/ActiveDirectoryUtils.cs +++ b/ActiveDirectoryConnector/ActiveDirectoryUtils.cs @@ -775,7 +775,7 @@ static internal LargeInteger GetLargeIntegerFromLong(Int64 int64Value) { LargeInteger largeInteger = new LargeIntegerClass(); largeInteger.HighPart = (int)(int64Value >> 32); ; - largeInteger.LowPart = (int)(int64Value & 0xFFFFFFFF); + largeInteger.LowPart = unchecked((int)(int64Value & 0xFFFFFFFF)); return largeInteger; } diff --git a/ActiveDirectoryConnector/CustomAttributeHandlers.cs b/ActiveDirectoryConnector/CustomAttributeHandlers.cs index 8eafb7c..66f8973 100644 --- a/ActiveDirectoryConnector/CustomAttributeHandlers.cs +++ b/ActiveDirectoryConnector/CustomAttributeHandlers.cs @@ -508,19 +508,7 @@ internal void UpdateDeFromCa_OpAtt_PasswordExpired(ObjectClass oclass, else { directoryEntry.Properties[ActiveDirectoryConnector.ATT_PWD_LAST_SET].Clear(); - Int64 int64Value = -1; - LargeInteger li = new LargeIntegerClass(); - li.HighPart = (int)(int64Value >> 32); - li.LowPart = (int)(int64Value & 0xFFFFFFFF); - directoryEntry.Properties[ActiveDirectoryConnector.ATT_PWD_LAST_SET].Value = li; - /* - // this value can't be set (other than to zero) I'm throwing my own exception - // here, because if not, AD thows this (at least on my machine): - // System.DirectoryServices.DirectoryServicesCOMException : A device attached to the system is not functioning. (Exception from HRESULT: 0x8007001F) - throw new ConnectorException(_configuration.ConnectorMessages.Format( - "ex_PasswordMustBeReset", - "Password expiration can only be reset by reseting the password")); - */ + directoryEntry.Properties[ActiveDirectoryConnector.ATT_PWD_LAST_SET].Value = ActiveDirectoryUtils.GetLargeIntegerFromLong(-1); } } From f91a9bc9182c0efbf25cf3a459f6b4c56f3b30e5 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Tue, 2 Jul 2024 14:06:20 +0300 Subject: [PATCH 33/33] Move to dotnet-connector/ --- .../ActiveDirectoryConnector}/ActiveDirectoryConfiguration.cs | 0 .../ActiveDirectoryConnector}/ActiveDirectoryConnector.cs | 0 .../ActiveDirectoryConnector}/ActiveDirectoryConnector.csproj | 0 .../ActiveDirectoryConnector}/ActiveDirectoryFilterTranslator.cs | 0 .../ActiveDirectoryConnector}/ActiveDirectorySyncToken.cs | 0 .../ActiveDirectoryConnector}/ActiveDirectoryUtils.cs | 0 .../ActiveDirectoryConnector}/CommonUtils.cs | 0 .../ActiveDirectoryConnector}/CustomAttributeHandlers.cs | 0 .../ActiveDirectoryConnector}/Messages.de-DE.resx | 0 .../ActiveDirectoryConnector}/Messages.en.Designer.cs | 0 .../ActiveDirectoryConnector}/Messages.en.resx | 0 .../ActiveDirectoryConnector}/Messages.es-ES.resx | 0 .../ActiveDirectoryConnector}/Messages.es.resx | 0 .../ActiveDirectoryConnector}/Messages.fr-FR.resx | 0 .../ActiveDirectoryConnector}/Messages.it-IT.resx | 0 .../ActiveDirectoryConnector}/Messages.ja-JP.resx | 0 .../ActiveDirectoryConnector}/Messages.ko-KR.resx | 0 .../ActiveDirectoryConnector}/Messages.pt-BR.resx | 0 .../ActiveDirectoryConnector}/Messages.resx | 0 .../ActiveDirectoryConnector}/Messages.zh-CN.resx | 0 .../ActiveDirectoryConnector}/Messages.zh-TW.resx | 0 .../ActiveDirectoryConnector}/ObjectClasses.xml | 0 .../ActiveDirectoryConnector}/PasswordChangeHandler.cs | 0 .../ActiveDirectoryConnector}/TerminalServicesUtils.cs | 0 .../ActiveDirectoryConnector}/UserAccountControl.cs | 0 .../ActiveDirectoryConnector}/version.template | 0 .../ActiveDirectoryConfigurationTests.cs | 0 .../ActiveDirectoryConnectorTest.cs | 0 .../ActiveDirectoryConnectorTests.csproj | 0 .../ActiveDirectoryConnectorTests}/ConfigHelper.cs | 0 .../config/config.xml | 0 .../ActiveDirectoryConnectorTests}/TestParams.resx | 0 .../ActiveDirectoryConnectorTests}/version.template | 0 .../DotNetCommonBuild.Targets | 0 DotNetConnectors.sln => dotnet-connector/DotNetConnectors.sln | 0 .../ExchangeConnector}/Data/CommandInfos.xml | 0 .../ExchangeConnector}/Data/PersistenceUtility.cs | 0 .../ExchangeConnector}/Data/SerializableCommandInfo.cs | 0 .../ExchangeConnector}/ExchangeConfiguration.cs | 0 .../ExchangeConnector}/ExchangeConnector.FxCop | 0 .../ExchangeConnector}/ExchangeConnector.cs | 0 .../ExchangeConnector}/ExchangeConnector.csproj | 0 .../ExchangeConnector}/ExchangeUtility.cs | 0 .../ExchangeConnector}/Messages.de-DE.resx | 0 .../ExchangeConnector}/Messages.es-ES.resx | 0 .../ExchangeConnector}/Messages.fr-FR.resx | 0 .../ExchangeConnector}/Messages.ja-JP.resx | 0 .../ExchangeConnector}/Messages.ko-KR.resx | 0 .../ExchangeConnector}/Messages.resx | 0 .../ExchangeConnector}/Messages.zh-CN.resx | 0 .../ExchangeConnector}/Messages.zh-TW.resx | 0 .../ExchangeConnector}/ObjectClasses.xml | 0 .../ExchangeConnector}/PSExchangeConnector.cs | 0 .../ExchangeConnector}/RunSpaceInstance.cs | 0 .../ExchangeConnector}/version.template | 0 {legal-notices => dotnet-connector/legal-notices}/CDDLv1_0.txt | 0 .../legal-notices}/ForgeRock_License.txt | 0 57 files changed, 0 insertions(+), 0 deletions(-) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/ActiveDirectoryConfiguration.cs (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/ActiveDirectoryConnector.cs (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/ActiveDirectoryConnector.csproj (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/ActiveDirectoryFilterTranslator.cs (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/ActiveDirectorySyncToken.cs (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/ActiveDirectoryUtils.cs (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/CommonUtils.cs (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/CustomAttributeHandlers.cs (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/Messages.de-DE.resx (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/Messages.en.Designer.cs (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/Messages.en.resx (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/Messages.es-ES.resx (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/Messages.es.resx (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/Messages.fr-FR.resx (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/Messages.it-IT.resx (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/Messages.ja-JP.resx (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/Messages.ko-KR.resx (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/Messages.pt-BR.resx (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/Messages.resx (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/Messages.zh-CN.resx (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/Messages.zh-TW.resx (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/ObjectClasses.xml (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/PasswordChangeHandler.cs (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/TerminalServicesUtils.cs (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/UserAccountControl.cs (100%) rename {ActiveDirectoryConnector => dotnet-connector/ActiveDirectoryConnector}/version.template (100%) rename {ActiveDirectoryConnectorTests => dotnet-connector/ActiveDirectoryConnectorTests}/ActiveDirectoryConfigurationTests.cs (100%) rename {ActiveDirectoryConnectorTests => dotnet-connector/ActiveDirectoryConnectorTests}/ActiveDirectoryConnectorTest.cs (100%) rename {ActiveDirectoryConnectorTests => dotnet-connector/ActiveDirectoryConnectorTests}/ActiveDirectoryConnectorTests.csproj (100%) rename {ActiveDirectoryConnectorTests => dotnet-connector/ActiveDirectoryConnectorTests}/ConfigHelper.cs (100%) rename {ActiveDirectoryConnectorTests => dotnet-connector/ActiveDirectoryConnectorTests}/Org.IdentityConnectors.ActiveDirectory.ActiveDirectoryConnector/config/config.xml (100%) rename {ActiveDirectoryConnectorTests => dotnet-connector/ActiveDirectoryConnectorTests}/TestParams.resx (100%) rename {ActiveDirectoryConnectorTests => dotnet-connector/ActiveDirectoryConnectorTests}/version.template (100%) rename DotNetCommonBuild.Targets => dotnet-connector/DotNetCommonBuild.Targets (100%) rename DotNetConnectors.sln => dotnet-connector/DotNetConnectors.sln (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/Data/CommandInfos.xml (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/Data/PersistenceUtility.cs (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/Data/SerializableCommandInfo.cs (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/ExchangeConfiguration.cs (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/ExchangeConnector.FxCop (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/ExchangeConnector.cs (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/ExchangeConnector.csproj (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/ExchangeUtility.cs (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/Messages.de-DE.resx (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/Messages.es-ES.resx (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/Messages.fr-FR.resx (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/Messages.ja-JP.resx (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/Messages.ko-KR.resx (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/Messages.resx (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/Messages.zh-CN.resx (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/Messages.zh-TW.resx (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/ObjectClasses.xml (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/PSExchangeConnector.cs (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/RunSpaceInstance.cs (100%) rename {ExchangeConnector => dotnet-connector/ExchangeConnector}/version.template (100%) rename {legal-notices => dotnet-connector/legal-notices}/CDDLv1_0.txt (100%) rename {legal-notices => dotnet-connector/legal-notices}/ForgeRock_License.txt (100%) diff --git a/ActiveDirectoryConnector/ActiveDirectoryConfiguration.cs b/dotnet-connector/ActiveDirectoryConnector/ActiveDirectoryConfiguration.cs similarity index 100% rename from ActiveDirectoryConnector/ActiveDirectoryConfiguration.cs rename to dotnet-connector/ActiveDirectoryConnector/ActiveDirectoryConfiguration.cs diff --git a/ActiveDirectoryConnector/ActiveDirectoryConnector.cs b/dotnet-connector/ActiveDirectoryConnector/ActiveDirectoryConnector.cs similarity index 100% rename from ActiveDirectoryConnector/ActiveDirectoryConnector.cs rename to dotnet-connector/ActiveDirectoryConnector/ActiveDirectoryConnector.cs diff --git a/ActiveDirectoryConnector/ActiveDirectoryConnector.csproj b/dotnet-connector/ActiveDirectoryConnector/ActiveDirectoryConnector.csproj similarity index 100% rename from ActiveDirectoryConnector/ActiveDirectoryConnector.csproj rename to dotnet-connector/ActiveDirectoryConnector/ActiveDirectoryConnector.csproj diff --git a/ActiveDirectoryConnector/ActiveDirectoryFilterTranslator.cs b/dotnet-connector/ActiveDirectoryConnector/ActiveDirectoryFilterTranslator.cs similarity index 100% rename from ActiveDirectoryConnector/ActiveDirectoryFilterTranslator.cs rename to dotnet-connector/ActiveDirectoryConnector/ActiveDirectoryFilterTranslator.cs diff --git a/ActiveDirectoryConnector/ActiveDirectorySyncToken.cs b/dotnet-connector/ActiveDirectoryConnector/ActiveDirectorySyncToken.cs similarity index 100% rename from ActiveDirectoryConnector/ActiveDirectorySyncToken.cs rename to dotnet-connector/ActiveDirectoryConnector/ActiveDirectorySyncToken.cs diff --git a/ActiveDirectoryConnector/ActiveDirectoryUtils.cs b/dotnet-connector/ActiveDirectoryConnector/ActiveDirectoryUtils.cs similarity index 100% rename from ActiveDirectoryConnector/ActiveDirectoryUtils.cs rename to dotnet-connector/ActiveDirectoryConnector/ActiveDirectoryUtils.cs diff --git a/ActiveDirectoryConnector/CommonUtils.cs b/dotnet-connector/ActiveDirectoryConnector/CommonUtils.cs similarity index 100% rename from ActiveDirectoryConnector/CommonUtils.cs rename to dotnet-connector/ActiveDirectoryConnector/CommonUtils.cs diff --git a/ActiveDirectoryConnector/CustomAttributeHandlers.cs b/dotnet-connector/ActiveDirectoryConnector/CustomAttributeHandlers.cs similarity index 100% rename from ActiveDirectoryConnector/CustomAttributeHandlers.cs rename to dotnet-connector/ActiveDirectoryConnector/CustomAttributeHandlers.cs diff --git a/ActiveDirectoryConnector/Messages.de-DE.resx b/dotnet-connector/ActiveDirectoryConnector/Messages.de-DE.resx similarity index 100% rename from ActiveDirectoryConnector/Messages.de-DE.resx rename to dotnet-connector/ActiveDirectoryConnector/Messages.de-DE.resx diff --git a/ActiveDirectoryConnector/Messages.en.Designer.cs b/dotnet-connector/ActiveDirectoryConnector/Messages.en.Designer.cs similarity index 100% rename from ActiveDirectoryConnector/Messages.en.Designer.cs rename to dotnet-connector/ActiveDirectoryConnector/Messages.en.Designer.cs diff --git a/ActiveDirectoryConnector/Messages.en.resx b/dotnet-connector/ActiveDirectoryConnector/Messages.en.resx similarity index 100% rename from ActiveDirectoryConnector/Messages.en.resx rename to dotnet-connector/ActiveDirectoryConnector/Messages.en.resx diff --git a/ActiveDirectoryConnector/Messages.es-ES.resx b/dotnet-connector/ActiveDirectoryConnector/Messages.es-ES.resx similarity index 100% rename from ActiveDirectoryConnector/Messages.es-ES.resx rename to dotnet-connector/ActiveDirectoryConnector/Messages.es-ES.resx diff --git a/ActiveDirectoryConnector/Messages.es.resx b/dotnet-connector/ActiveDirectoryConnector/Messages.es.resx similarity index 100% rename from ActiveDirectoryConnector/Messages.es.resx rename to dotnet-connector/ActiveDirectoryConnector/Messages.es.resx diff --git a/ActiveDirectoryConnector/Messages.fr-FR.resx b/dotnet-connector/ActiveDirectoryConnector/Messages.fr-FR.resx similarity index 100% rename from ActiveDirectoryConnector/Messages.fr-FR.resx rename to dotnet-connector/ActiveDirectoryConnector/Messages.fr-FR.resx diff --git a/ActiveDirectoryConnector/Messages.it-IT.resx b/dotnet-connector/ActiveDirectoryConnector/Messages.it-IT.resx similarity index 100% rename from ActiveDirectoryConnector/Messages.it-IT.resx rename to dotnet-connector/ActiveDirectoryConnector/Messages.it-IT.resx diff --git a/ActiveDirectoryConnector/Messages.ja-JP.resx b/dotnet-connector/ActiveDirectoryConnector/Messages.ja-JP.resx similarity index 100% rename from ActiveDirectoryConnector/Messages.ja-JP.resx rename to dotnet-connector/ActiveDirectoryConnector/Messages.ja-JP.resx diff --git a/ActiveDirectoryConnector/Messages.ko-KR.resx b/dotnet-connector/ActiveDirectoryConnector/Messages.ko-KR.resx similarity index 100% rename from ActiveDirectoryConnector/Messages.ko-KR.resx rename to dotnet-connector/ActiveDirectoryConnector/Messages.ko-KR.resx diff --git a/ActiveDirectoryConnector/Messages.pt-BR.resx b/dotnet-connector/ActiveDirectoryConnector/Messages.pt-BR.resx similarity index 100% rename from ActiveDirectoryConnector/Messages.pt-BR.resx rename to dotnet-connector/ActiveDirectoryConnector/Messages.pt-BR.resx diff --git a/ActiveDirectoryConnector/Messages.resx b/dotnet-connector/ActiveDirectoryConnector/Messages.resx similarity index 100% rename from ActiveDirectoryConnector/Messages.resx rename to dotnet-connector/ActiveDirectoryConnector/Messages.resx diff --git a/ActiveDirectoryConnector/Messages.zh-CN.resx b/dotnet-connector/ActiveDirectoryConnector/Messages.zh-CN.resx similarity index 100% rename from ActiveDirectoryConnector/Messages.zh-CN.resx rename to dotnet-connector/ActiveDirectoryConnector/Messages.zh-CN.resx diff --git a/ActiveDirectoryConnector/Messages.zh-TW.resx b/dotnet-connector/ActiveDirectoryConnector/Messages.zh-TW.resx similarity index 100% rename from ActiveDirectoryConnector/Messages.zh-TW.resx rename to dotnet-connector/ActiveDirectoryConnector/Messages.zh-TW.resx diff --git a/ActiveDirectoryConnector/ObjectClasses.xml b/dotnet-connector/ActiveDirectoryConnector/ObjectClasses.xml similarity index 100% rename from ActiveDirectoryConnector/ObjectClasses.xml rename to dotnet-connector/ActiveDirectoryConnector/ObjectClasses.xml diff --git a/ActiveDirectoryConnector/PasswordChangeHandler.cs b/dotnet-connector/ActiveDirectoryConnector/PasswordChangeHandler.cs similarity index 100% rename from ActiveDirectoryConnector/PasswordChangeHandler.cs rename to dotnet-connector/ActiveDirectoryConnector/PasswordChangeHandler.cs diff --git a/ActiveDirectoryConnector/TerminalServicesUtils.cs b/dotnet-connector/ActiveDirectoryConnector/TerminalServicesUtils.cs similarity index 100% rename from ActiveDirectoryConnector/TerminalServicesUtils.cs rename to dotnet-connector/ActiveDirectoryConnector/TerminalServicesUtils.cs diff --git a/ActiveDirectoryConnector/UserAccountControl.cs b/dotnet-connector/ActiveDirectoryConnector/UserAccountControl.cs similarity index 100% rename from ActiveDirectoryConnector/UserAccountControl.cs rename to dotnet-connector/ActiveDirectoryConnector/UserAccountControl.cs diff --git a/ActiveDirectoryConnector/version.template b/dotnet-connector/ActiveDirectoryConnector/version.template similarity index 100% rename from ActiveDirectoryConnector/version.template rename to dotnet-connector/ActiveDirectoryConnector/version.template diff --git a/ActiveDirectoryConnectorTests/ActiveDirectoryConfigurationTests.cs b/dotnet-connector/ActiveDirectoryConnectorTests/ActiveDirectoryConfigurationTests.cs similarity index 100% rename from ActiveDirectoryConnectorTests/ActiveDirectoryConfigurationTests.cs rename to dotnet-connector/ActiveDirectoryConnectorTests/ActiveDirectoryConfigurationTests.cs diff --git a/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTest.cs b/dotnet-connector/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTest.cs similarity index 100% rename from ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTest.cs rename to dotnet-connector/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTest.cs diff --git a/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTests.csproj b/dotnet-connector/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTests.csproj similarity index 100% rename from ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTests.csproj rename to dotnet-connector/ActiveDirectoryConnectorTests/ActiveDirectoryConnectorTests.csproj diff --git a/ActiveDirectoryConnectorTests/ConfigHelper.cs b/dotnet-connector/ActiveDirectoryConnectorTests/ConfigHelper.cs similarity index 100% rename from ActiveDirectoryConnectorTests/ConfigHelper.cs rename to dotnet-connector/ActiveDirectoryConnectorTests/ConfigHelper.cs diff --git a/ActiveDirectoryConnectorTests/Org.IdentityConnectors.ActiveDirectory.ActiveDirectoryConnector/config/config.xml b/dotnet-connector/ActiveDirectoryConnectorTests/Org.IdentityConnectors.ActiveDirectory.ActiveDirectoryConnector/config/config.xml similarity index 100% rename from ActiveDirectoryConnectorTests/Org.IdentityConnectors.ActiveDirectory.ActiveDirectoryConnector/config/config.xml rename to dotnet-connector/ActiveDirectoryConnectorTests/Org.IdentityConnectors.ActiveDirectory.ActiveDirectoryConnector/config/config.xml diff --git a/ActiveDirectoryConnectorTests/TestParams.resx b/dotnet-connector/ActiveDirectoryConnectorTests/TestParams.resx similarity index 100% rename from ActiveDirectoryConnectorTests/TestParams.resx rename to dotnet-connector/ActiveDirectoryConnectorTests/TestParams.resx diff --git a/ActiveDirectoryConnectorTests/version.template b/dotnet-connector/ActiveDirectoryConnectorTests/version.template similarity index 100% rename from ActiveDirectoryConnectorTests/version.template rename to dotnet-connector/ActiveDirectoryConnectorTests/version.template diff --git a/DotNetCommonBuild.Targets b/dotnet-connector/DotNetCommonBuild.Targets similarity index 100% rename from DotNetCommonBuild.Targets rename to dotnet-connector/DotNetCommonBuild.Targets diff --git a/DotNetConnectors.sln b/dotnet-connector/DotNetConnectors.sln similarity index 100% rename from DotNetConnectors.sln rename to dotnet-connector/DotNetConnectors.sln diff --git a/ExchangeConnector/Data/CommandInfos.xml b/dotnet-connector/ExchangeConnector/Data/CommandInfos.xml similarity index 100% rename from ExchangeConnector/Data/CommandInfos.xml rename to dotnet-connector/ExchangeConnector/Data/CommandInfos.xml diff --git a/ExchangeConnector/Data/PersistenceUtility.cs b/dotnet-connector/ExchangeConnector/Data/PersistenceUtility.cs similarity index 100% rename from ExchangeConnector/Data/PersistenceUtility.cs rename to dotnet-connector/ExchangeConnector/Data/PersistenceUtility.cs diff --git a/ExchangeConnector/Data/SerializableCommandInfo.cs b/dotnet-connector/ExchangeConnector/Data/SerializableCommandInfo.cs similarity index 100% rename from ExchangeConnector/Data/SerializableCommandInfo.cs rename to dotnet-connector/ExchangeConnector/Data/SerializableCommandInfo.cs diff --git a/ExchangeConnector/ExchangeConfiguration.cs b/dotnet-connector/ExchangeConnector/ExchangeConfiguration.cs similarity index 100% rename from ExchangeConnector/ExchangeConfiguration.cs rename to dotnet-connector/ExchangeConnector/ExchangeConfiguration.cs diff --git a/ExchangeConnector/ExchangeConnector.FxCop b/dotnet-connector/ExchangeConnector/ExchangeConnector.FxCop similarity index 100% rename from ExchangeConnector/ExchangeConnector.FxCop rename to dotnet-connector/ExchangeConnector/ExchangeConnector.FxCop diff --git a/ExchangeConnector/ExchangeConnector.cs b/dotnet-connector/ExchangeConnector/ExchangeConnector.cs similarity index 100% rename from ExchangeConnector/ExchangeConnector.cs rename to dotnet-connector/ExchangeConnector/ExchangeConnector.cs diff --git a/ExchangeConnector/ExchangeConnector.csproj b/dotnet-connector/ExchangeConnector/ExchangeConnector.csproj similarity index 100% rename from ExchangeConnector/ExchangeConnector.csproj rename to dotnet-connector/ExchangeConnector/ExchangeConnector.csproj diff --git a/ExchangeConnector/ExchangeUtility.cs b/dotnet-connector/ExchangeConnector/ExchangeUtility.cs similarity index 100% rename from ExchangeConnector/ExchangeUtility.cs rename to dotnet-connector/ExchangeConnector/ExchangeUtility.cs diff --git a/ExchangeConnector/Messages.de-DE.resx b/dotnet-connector/ExchangeConnector/Messages.de-DE.resx similarity index 100% rename from ExchangeConnector/Messages.de-DE.resx rename to dotnet-connector/ExchangeConnector/Messages.de-DE.resx diff --git a/ExchangeConnector/Messages.es-ES.resx b/dotnet-connector/ExchangeConnector/Messages.es-ES.resx similarity index 100% rename from ExchangeConnector/Messages.es-ES.resx rename to dotnet-connector/ExchangeConnector/Messages.es-ES.resx diff --git a/ExchangeConnector/Messages.fr-FR.resx b/dotnet-connector/ExchangeConnector/Messages.fr-FR.resx similarity index 100% rename from ExchangeConnector/Messages.fr-FR.resx rename to dotnet-connector/ExchangeConnector/Messages.fr-FR.resx diff --git a/ExchangeConnector/Messages.ja-JP.resx b/dotnet-connector/ExchangeConnector/Messages.ja-JP.resx similarity index 100% rename from ExchangeConnector/Messages.ja-JP.resx rename to dotnet-connector/ExchangeConnector/Messages.ja-JP.resx diff --git a/ExchangeConnector/Messages.ko-KR.resx b/dotnet-connector/ExchangeConnector/Messages.ko-KR.resx similarity index 100% rename from ExchangeConnector/Messages.ko-KR.resx rename to dotnet-connector/ExchangeConnector/Messages.ko-KR.resx diff --git a/ExchangeConnector/Messages.resx b/dotnet-connector/ExchangeConnector/Messages.resx similarity index 100% rename from ExchangeConnector/Messages.resx rename to dotnet-connector/ExchangeConnector/Messages.resx diff --git a/ExchangeConnector/Messages.zh-CN.resx b/dotnet-connector/ExchangeConnector/Messages.zh-CN.resx similarity index 100% rename from ExchangeConnector/Messages.zh-CN.resx rename to dotnet-connector/ExchangeConnector/Messages.zh-CN.resx diff --git a/ExchangeConnector/Messages.zh-TW.resx b/dotnet-connector/ExchangeConnector/Messages.zh-TW.resx similarity index 100% rename from ExchangeConnector/Messages.zh-TW.resx rename to dotnet-connector/ExchangeConnector/Messages.zh-TW.resx diff --git a/ExchangeConnector/ObjectClasses.xml b/dotnet-connector/ExchangeConnector/ObjectClasses.xml similarity index 100% rename from ExchangeConnector/ObjectClasses.xml rename to dotnet-connector/ExchangeConnector/ObjectClasses.xml diff --git a/ExchangeConnector/PSExchangeConnector.cs b/dotnet-connector/ExchangeConnector/PSExchangeConnector.cs similarity index 100% rename from ExchangeConnector/PSExchangeConnector.cs rename to dotnet-connector/ExchangeConnector/PSExchangeConnector.cs diff --git a/ExchangeConnector/RunSpaceInstance.cs b/dotnet-connector/ExchangeConnector/RunSpaceInstance.cs similarity index 100% rename from ExchangeConnector/RunSpaceInstance.cs rename to dotnet-connector/ExchangeConnector/RunSpaceInstance.cs diff --git a/ExchangeConnector/version.template b/dotnet-connector/ExchangeConnector/version.template similarity index 100% rename from ExchangeConnector/version.template rename to dotnet-connector/ExchangeConnector/version.template diff --git a/legal-notices/CDDLv1_0.txt b/dotnet-connector/legal-notices/CDDLv1_0.txt similarity index 100% rename from legal-notices/CDDLv1_0.txt rename to dotnet-connector/legal-notices/CDDLv1_0.txt diff --git a/legal-notices/ForgeRock_License.txt b/dotnet-connector/legal-notices/ForgeRock_License.txt similarity index 100% rename from legal-notices/ForgeRock_License.txt rename to dotnet-connector/legal-notices/ForgeRock_License.txt