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);

            builder             = new SyncDeltaBuilder();
            builder.DeltaType   = SyncDeltaType.DELETE;
            builder.Token       = new SyncToken("mytoken");
            builder.ObjectClass = ObjectClass.ACCOUNT;
            builder.Uid         = new Uid("foo");
            v1 = builder.Build();
            v2 = (SyncDelta)CloneObject(v1);
            Assert.AreEqual(ObjectClass.ACCOUNT, v2.ObjectClass);
            Assert.AreEqual(new Uid("foo"), v2.Uid);
            Assert.AreEqual(new SyncToken("mytoken"), v2.Token);
            Assert.AreEqual(SyncDeltaType.DELETE, v2.DeltaType);
            Assert.AreEqual(v1, v2);
        }
Пример #2
0
        /// <summary>
        /// Finds the attributes in connector object and rename it according to input array of names, but only
        /// if the atribute name is in attributes to get
        /// </summary>
        /// <param name="cobject">ConnectorObject which attributes should be replaced</param>
        /// <param name="attsToGet">Attributes to get list</param>
        /// <param name="map">Replace mapping</param>
        /// <returns>ConnectorObject with replaced attributes</returns>
        /// <exception cref="ArgumentNullException">If some of the params is null</exception>
        internal static ConnectorObject ReplaceAttributes(ConnectorObject cobject, ICollection <string> attsToGet, IDictionary <string, string> map)
        {
            Assertions.NullCheck(cobject, "cobject");
            Assertions.NullCheck(map, "map");
            if (attsToGet == null)
            {
                return(cobject);
            }

            var attributes = cobject.GetAttributes();
            var builder    = new ConnectorObjectBuilder();

            foreach (ConnectorAttribute attribute in attributes)
            {
                string newName;
                if (map.TryGetValue(attribute.Name, out newName) && attsToGet.Contains(newName))
                {
                    var newAttribute = RenameAttribute(attribute, newName);
                    builder.AddAttribute(newAttribute);
                    break;
                }

                builder.AddAttribute(attribute);
            }

            builder.AddAttributes(attributes);
            builder.ObjectClass = cobject.ObjectClass;
            builder.SetName(cobject.Name);
            builder.SetUid(cobject.Uid);
            return(builder.Build());
        }
        public void Sync(ObjectClass objClass, SyncToken token,
                         SyncResultsHandler handler,
                         OperationOptions options)
        {
            int remaining = _config.numResults;

            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.Handle(rv))
                {
                    remaining--;
                }
                else
                {
                    break;;
                }
            }
            if (handler is SyncTokenResultsHandler)
            {
                ((SyncTokenResultsHandler)handler).HandleResult(new SyncToken(remaining));
            }
        }
Пример #4
0
        internal ConnectorObject CreateConnectorObject(ExchangeConnector connector, PSObject psobject, ObjectClass objectClass)
        {
            ConnectorObjectBuilder builder = new ConnectorObjectBuilder();

            string guid = (string)psobject.Properties["guid"].Value.ToString();
            string name = (string)psobject.Properties["name"].Value;

            builder.SetUid(new Uid(guid));
            builder.SetName(new Name(name));

            ObjectClassInfo ocinfo = connector.GetSchema().FindObjectClassInfo(objectClass.GetObjectClassValue());

            IDictionary <string, PSPropertyInfo> properties = psobject.Properties.ToDictionary(psinfo => psinfo.Name);

            LOG.Trace("Building connector object with UID = {0} and Name = {1}", guid, name);
            foreach (ConnectorAttributeInfo cai in ocinfo.ConnectorAttributeInfos)
            {
                if (cai.IsReadable && properties.ContainsKey(cai.Name))
                {
                    object value = properties[cai.Name].Value;
                    LOG.Trace(" - attribute {0} = {1}", cai.Name, value);

                    if (value is PSObject)
                    {
                        var ps = value as PSObject;
                        value = ps.BaseObject;
                        LOG.Trace(" - attribute {0} UNWRAPPED = {1} ({2})", cai.Name, value, value.GetType());
                    }
                    builder.AddAttribute(cai.Name, CommonUtils.ConvertToSupportedForm(cai, value));
                }
            }
            return(builder.Build());
        }
Пример #5
0
 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;
         }
     }
 }
Пример #6
0
        private void SubmitConnectorObject(String result, ResultsHandler handler)
        {
            ConnectorObjectBuilder cob = new ConnectorObjectBuilder();

            String[] resultSplit = result.Split(new char[] { '$' });
            ICollection <ConnectorAttribute> attrs = new List <ConnectorAttribute>();

            foreach (String str in resultSplit)
            {
                ConnectorAttributeBuilder cab = new ConnectorAttributeBuilder();
                cab.AddValue(str.Split(new char[] { ':' })[1]);

                if (str.StartsWith("Name"))
                {
                    cob.SetName(Name.NAME);
                    cob.SetUid(str.Split(new char[] { ':' })[1]);
                    cab.Name = Name.NAME;
                }
                else
                {
                    cab.Name = str.Split(new char[] { ':' })[0];
                }

                attrs.Add(cab.Build());
            }

            cob.AddAttributes(attrs);
            handler(cob.Build());
        }
Пример #7
0
        /// <summary>
        /// Finds the attributes in connector object and rename it according to input array of names, but only
        /// if the atribute name is in attributes to get
        /// </summary>
        /// <param name="cobject">ConnectorObject which attributes should be replaced</param>
        /// <param name="map">Replace mapping</param>
        /// <returns>ConnectorObject with replaced attributes</returns>
        /// <exception cref="ArgumentNullException">If some of the params is null</exception>
        internal static ConnectorObject ConvertAdAttributesToExchange(ConnectorObject cobject)
        {
            Assertions.NullCheck(cobject, "cobject");

            var attributes = cobject.GetAttributes();
            var builder    = new ConnectorObjectBuilder();

            bool emailAddressPolicyEnabled = true;

            foreach (ConnectorAttribute attribute in attributes)
            {
                string newName;
                if (attribute.Is(ExchangeConnectorAttributes.AttMsExchPoliciesExcludedADName))
                {
                    if (attribute.Value != null && attribute.Value.Contains("{26491cfc-9e50-4857-861b-0cb8df22b5d7}"))
                    {
                        emailAddressPolicyEnabled = false;
                    }
                }
                else if (attribute.Is(ExchangeConnectorAttributes.AttAddressBookPolicyADName))
                {
                    var newAttribute = ExtractCommonName(attribute, ExchangeConnectorAttributes.AttAddressBookPolicy);
                    builder.AddAttribute(newAttribute);
                    builder.AddAttribute(attribute);        // keep the original one as well
                }
                else if (attribute.Is(ExchangeConnectorAttributes.AttOfflineAddressBookADName))
                {
                    var newAttribute = ExtractCommonName(attribute, ExchangeConnectorAttributes.AttOfflineAddressBook);
                    builder.AddAttribute(newAttribute);
                    builder.AddAttribute(attribute);        // keep the original one as well
                }
                else if (ExchangeConnectorAttributes.AttMapFromAD.TryGetValue(attribute.Name, out newName))
                {
                    var newAttribute = RenameAttribute(attribute, newName);
                    builder.AddAttribute(newAttribute);
                }
                else
                {
                    builder.AddAttribute(attribute);
                }
            }

            builder.AddAttribute(ConnectorAttributeBuilder.Build(ExchangeConnectorAttributes.AttEmailAddressPolicyEnabled, emailAddressPolicyEnabled));

            copyAttribute(builder, cobject, ExchangeConnectorAttributes.AttPrimarySmtpAddressADName, ExchangeConnectorAttributes.AttPrimarySmtpAddress);

            // derive recipient type
            string recipientType = GetRecipientType(cobject);

            if (recipientType != null)
            {
                builder.AddAttribute(ConnectorAttributeBuilder.Build(ExchangeConnectorAttributes.AttRecipientType, new string[] { recipientType }));
            }

            builder.ObjectClass = cobject.ObjectClass;
            builder.SetName(cobject.Name);
            builder.SetUid(cobject.Uid);
            return(builder.Build());
        }
        public Object Process(Object result)
        {
            if (result == null)
            {
                return(true);
            }

            if (result is ConnectorObject)
            {
                return(_handler.Handle(result as ConnectorObject));
            }

            var cobld = new ConnectorObjectBuilder();
            var res   = result as Hashtable;

            foreach (String key in res.Keys)
            {
                var attrName  = key;
                var attrValue = res[key];
                if ("__UID__".Equals(attrName))
                {
                    if (attrValue == null)
                    {
                        throw new ConnectorException("Uid can not be null");
                    }
                    cobld.SetUid(attrValue.ToString());
                }
                else if ("__NAME__".Equals(attrName))
                {
                    if (attrValue == null)
                    {
                        throw new ConnectorException("Name can not be null");
                    }
                    cobld.SetName(attrValue.ToString());
                }
                else
                {
                    if (attrValue == null)
                    {
                        cobld.AddAttribute(ConnectorAttributeBuilder.Build(attrName));
                    }
                    else if (attrValue.GetType() == typeof(Object[]) || attrValue.GetType() == typeof(System.Collections.ICollection))
                    {
                        var list = new Collection <object>();
                        foreach (var val in (ICollection)attrValue)
                        {
                            list.Add(FrameworkUtil.IsSupportedAttributeType(val.GetType()) ? val : val.ToString());
                        }
                        cobld.AddAttribute(ConnectorAttributeBuilder.Build(attrName, list));
                    }
                    else
                    {
                        cobld.AddAttribute(ConnectorAttributeBuilder.Build(attrName, attrValue));
                    }
                }
            }
            cobld.ObjectClass = _objectClass;
            return(_handler.Handle(cobld.Build()));
        }
Пример #9
0
        private static void copyAttribute(ConnectorObjectBuilder builder, ConnectorObject cobject, string src, string dest)
        {
            ConnectorAttribute srcAttr = cobject.GetAttributeByName(src);

            if (srcAttr != null)
            {
                builder.AddAttribute(RenameAttribute(srcAttr, dest));
            }
        }
Пример #10
0
        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());
            }
        }
        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);
        }
Пример #12
0
        /// <summary>
        /// This will do a basic replace.
        /// </summary>
        ///
        /// <seealso cref="UpdateOp.Update"/>
        ///
        public Uid Update(ObjectClass objclass, Uid uid, ICollection <ConnectorAttribute> 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);
        }
Пример #13
0
        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));
        }
Пример #14
0
        public virtual void Sync(ObjectClass objectClass, SyncToken token, SyncResultsHandler handler,
                                 OperationOptions options)
        {
            if (ObjectClass.ALL.Equals(objectClass))
            {
                //
            }
            else if (ObjectClass.ACCOUNT.Equals(objectClass))
            {
                var builder = new ConnectorObjectBuilder();
                builder.SetUid("3f50eca0-f5e9-11e3-a3ac-0800200c9a66");
                builder.SetName("Foo");
                builder.AddAttribute(ConnectorAttributeBuilder.BuildEnabled(true));

                var deltaBuilder = new SyncDeltaBuilder
                {
                    Object    = builder.Build(),
                    DeltaType = SyncDeltaType.CREATE,
                    Token     = new SyncToken(10)
                };

                foreach (SyncDelta connectorObject in CollectionUtil.NewSet(deltaBuilder.Build()))
                {
                    if (!handler.Handle(connectorObject))
                    {
                        // Stop iterating because the handler stopped processing
                        break;
                    }
                }
            }
            else
            {
                Trace.TraceWarning("Sync of type {0} is not supported",
                                   _configuration.ConnectorMessages.Format(objectClass.GetDisplayNameKey(),
                                                                           objectClass.GetObjectClassValue()));
                throw new NotSupportedException("Sync of type" + objectClass.GetObjectClassValue() + " is not supported");
            }
            ((SyncTokenResultsHandler)handler).HandleResult(new SyncToken(10));
        }
        static TstAbstractConnector()
        {
            bool enabled = true;

            for (int i = 0; i < 100; i++)
            {
                ConnectorObjectBuilder builder = new ConnectorObjectBuilder();
                builder.SetUid(Convert.ToString(i));
                builder.SetName(string.Format("user{0:D3}", i));
                builder.AddAttribute(ConnectorAttributeBuilder.BuildEnabled(enabled));
                IDictionary <string, object> mapAttribute = new Dictionary <string, object>();
                mapAttribute["email"]   = "*****@*****.**";
                mapAttribute["primary"] = true;
                mapAttribute["usage"]   = new List <String>()
                {
                    "home", "work"
                };
                builder.AddAttribute("emails", mapAttribute);
                ConnectorObject co = builder.Build();
                collection[co.Name.GetNameValue()] = co;
                enabled = !enabled;
            }
        }
Пример #16
0
        public virtual void ExecuteQuery(ObjectClass objectClass, string query, ResultsHandler handler,
                                         OperationOptions options)
        {
            var builder = new ConnectorObjectBuilder();

            builder.SetUid("3f50eca0-f5e9-11e3-a3ac-0800200c9a66");
            builder.SetName("Foo");
            builder.AddAttribute(ConnectorAttributeBuilder.BuildEnabled(true));

            foreach (ConnectorObject connectorObject in CollectionUtil.NewSet(builder.Build()))
            {
                if (!handler.Handle(connectorObject))
                {
                    // Stop iterating because the handler stopped processing
                    break;
                }
            }
            if (options.PageSize != null && 0 < options.PageSize)
            {
                Trace.TraceInformation("Paged Search was requested");
                ((SearchResultsHandler)handler).HandleResult(new SearchResult("0", 0));
            }
        }
Пример #17
0
        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;
                }
            }
        }
Пример #18
0
        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));
        }
        /// <summary>
        /// Gets Recipient Type/Database from Exchange database, this method can be more general, but it is ok
        /// for out needs
        /// </summary>
        /// <param name="oc">object class, currently the moethod works for <see cref="ObjectClass.ACCOUNT"/> only</param>
        /// <param name="cobject">connector object to get the recipient type/database for</param>
        /// <param name="attToGet">attributes to get</param>
        /// <returns>Connector Object with recipient type added</returns>
        /// <exception cref="ConnectorException">In case of some troubles in powershell (if the
        /// user is not found we get this exception too)</exception>
        private ConnectorObject AddExchangeAttributes(ObjectClass oc, ConnectorObject cobject, IEnumerable <string> attToGet)
        {
            ExchangeUtility.NullCheck(oc, "name", this.configuration);
            ExchangeUtility.NullCheck(oc, "cobject", this.configuration);

            // we support ACCOUNT only or there is nothing to add
            if (!oc.Is(ObjectClass.ACCOUNT_NAME) || attToGet == null)
            {
                return(cobject);
            }

            // check it is not deleted object
            bool?deleted = ExchangeUtility.GetAttValue(AttIsDeleted, cobject.GetAttributes()) as bool?;

            if (deleted != null && deleted == true)
            {
                // do nothing, it is deleted object
                return(cobject);
            }

            ICollection <string> lattToGet = CollectionUtil.NewCaseInsensitiveSet();

            CollectionUtil.AddAll(lattToGet, attToGet);
            foreach (string att in attToGet)
            {
                if (cobject.GetAttributeByName(att) != null && att != AttDatabase)
                {
                    lattToGet.Remove(att);
                }
            }

            if (lattToGet.Count == 0)
            {
                return(cobject);
            }

            ConnectorObjectBuilder cobjBuilder = new ConnectorObjectBuilder();

            cobjBuilder.AddAttributes(cobject.GetAttributes());

            PSExchangeConnector.CommandInfo cmdInfo = PSExchangeConnector.CommandInfo.GetUser;

            // prepare the connector attribute list to get the command
            ICollection <ConnectorAttribute> attributes = new Collection <ConnectorAttribute> {
                cobject.Name
            };

            // get the command
            Command cmd = ExchangeUtility.GetCommand(cmdInfo, attributes, this.configuration);
            ICollection <PSObject> foundObjects = this.InvokePipeline(cmd);
            PSObject user = null;

            if (foundObjects != null && foundObjects.Count == 1)
            {
                user = GetFirstElement(foundObjects);
                foreach (var info in user.Properties)
                {
                    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)
            {
                // nothing to do
                return(cobject);
            }

            string rcptType = user.Members[AttRecipientType].Value.ToString();

            foundObjects = null;

            // get detailed information
            if (rcptType == RcptTypeMailBox)
            {
                foundObjects = this.InvokePipeline(ExchangeUtility.GetCommand(PSExchangeConnector.CommandInfo.GetMailbox, attributes, this.configuration));
            }
            else if (rcptType == RcptTypeMailUser)
            {
                foundObjects = this.InvokePipeline(ExchangeUtility.GetCommand(PSExchangeConnector.CommandInfo.GetMailUser, attributes, this.configuration));
            }

            if (foundObjects != null && foundObjects.Count == 1)
            {
                PSObject userDetails = GetFirstElement(foundObjects);
                foreach (var info in userDetails.Properties)
                {
                    ConnectorAttribute att = GetAsAttribute(info);
                    if (att != null && lattToGet.Contains(att.Name))
                    {
                        cobjBuilder.AddAttribute(att);
                        lattToGet.Remove(att.Name);
                    }
                }
            }

            return(cobjBuilder.Build());
        }
Пример #20
0
        /// <summary>
        /// Process the Hashtable result and convert it to a SyncDelta object
        /// ready to be processed by the sync handler
        /// </summary>
        /// <remarks>
        /// The result Hashtable must follow a specific format and contain the following key/value:
        ///
        /// "Token": (Object) token object (could be Integer, Date, String), [!! could be null]
        /// "DeltaType": (String) ("CREATE|UPDATE|CREATE_OR_UPDATE"|"DELETE"),
        /// "Uid": (String) uid  (uid of the entry),
        /// "PreviousUid": (String) previous uid (This is for rename ops),
        /// "Object": Hashtable(String,List) of attributes name/values describing the object
        /// "ObjectClass": (String) must be set if Operation = DELETE and Object = null
        /// </remarks>
        /// <param name="result"></param>
        /// <returns></returns>
        public Object Process(Hashtable result)
        {
            var syncbld = new SyncDeltaBuilder();
            var cobld   = new ConnectorObjectBuilder();
            Uid uid;

            // SyncToken
            // Mandatory here
            if (result.ContainsKey(SyncTokenKeyName))
            {
                syncbld.Token = result[SyncTokenKeyName] == null ? new SyncToken(0L) : new SyncToken(result[SyncTokenKeyName]);
            }
            else
            {
                throw new ArgumentException("SyncToken is missing in Sync result");
            }

            // SyncDelta
            // Mandatory here
            if (isValidKeyAndValue(result, DeltaTypeKeyName))
            {
                var op = result[DeltaTypeKeyName];
                if (SyncDeltaType.CREATE.ToString().Equals(op as String, StringComparison.OrdinalIgnoreCase))
                {
                    syncbld.DeltaType = SyncDeltaType.CREATE;
                }
                else if (SyncDeltaType.UPDATE.ToString().Equals(op as String, StringComparison.OrdinalIgnoreCase))
                {
                    syncbld.DeltaType = SyncDeltaType.UPDATE;
                }
                else if (SyncDeltaType.DELETE.ToString().Equals(op as String, StringComparison.OrdinalIgnoreCase))
                {
                    syncbld.DeltaType = SyncDeltaType.DELETE;
                }
                else if (SyncDeltaType.CREATE_OR_UPDATE.ToString().Equals(op as String, StringComparison.OrdinalIgnoreCase))
                {
                    syncbld.DeltaType = SyncDeltaType.CREATE_OR_UPDATE;
                }
                else
                {
                    throw new ArgumentException("Unrecognized DeltaType in Sync result");
                }
            }
            else
            {
                throw new ArgumentException("DeltaType is missing in Sync result");
            }

            // Uid
            // Mandatory
            if (isValidKeyAndValue(result, UidKeyName))
            {
                var value = result[UidKeyName];
                if (value is String)
                {
                    uid = new Uid(value as String);
                }
                else if (value is Uid)
                {
                    uid = value as Uid;
                }
                else
                {
                    throw new ArgumentException("Unrecognized Uid in Sync result");
                }
                syncbld.Uid = uid;
                cobld.SetUid(uid);
            }
            else
            {
                throw new ArgumentException("Uid is missing in Sync result");
            }

            // PreviousUid
            // Not valid if DELETE
            if (isValidKeyAndValue(result, PreviousUidKeyName))
            {
                var value = result[PreviousUidKeyName];
                Uid previousUid;
                if (value is String)
                {
                    previousUid = new Uid(value as String);
                }
                else if (value is Uid)
                {
                    previousUid = value as Uid;
                }
                else
                {
                    throw new ArgumentException("Unrecognized PreviousUid in Sync result");
                }
                syncbld.PreviousUid = previousUid;
            }
            if (syncbld.PreviousUid != null && syncbld.DeltaType == SyncDeltaType.DELETE)
            {
                throw new ArgumentException("PreviousUid can only be specified for Create or Update.");
            }

            // Connector object
            // Mandatory unless DELETE
            if (result.ContainsKey(ConnectorObjectKeyName) && result[ConnectorObjectKeyName] is Hashtable)
            {
                var attrs = result[ConnectorObjectKeyName] as Hashtable;

                if (!attrs.ContainsKey(Name.NAME))
                {
                    throw new ArgumentException("The Object must contain a Name");
                }

                foreach (DictionaryEntry attr in attrs)
                {
                    var attrName  = attr.Key as String;
                    var attrValue = attr.Value;

                    if (Name.NAME.Equals(attrName))
                    {
                        cobld.SetName(attrValue as String);
                    }
                    else if (Uid.NAME.Equals((attrName)))
                    {
                        if (!uid.GetUidValue().Equals(attrValue))
                        {
                            throw new ArgumentException("Uid from Object is different than Uid from Sync result");
                        }
                    }
                    else if (OperationalAttributes.ENABLE_NAME.Equals((attrName)))
                    {
                        cobld.AddAttribute(ConnectorAttributeBuilder.BuildEnabled(attr.Value is bool && (bool)attr.Value));
                    }
                    else
                    {
                        if (attrValue == null)
                        {
                            cobld.AddAttribute(ConnectorAttributeBuilder.Build(attrName));
                        }
                        else if (attrValue.GetType() == typeof(Object[]) || attrValue.GetType() == typeof(System.Collections.ICollection))
                        {
                            var list = new Collection <object>();
                            foreach (var val in (ICollection)attrValue)
                            {
                                list.Add(FrameworkUtil.IsSupportedAttributeType(val.GetType()) ? val : val.ToString());
                            }
                            cobld.AddAttribute(ConnectorAttributeBuilder.Build(attrName, list));
                        }
                        else
                        {
                            cobld.AddAttribute(ConnectorAttributeBuilder.Build(attrName, attrValue));
                        }
                    }
                }
                cobld.ObjectClass = _objectClass;
                syncbld.Object    = cobld.Build();
            }
            // If operation is DELETE and the ConnectorObject is null,
            // we need to set the ObjectClass at the SyncDelta level
            else if ((SyncDeltaType.DELETE == syncbld.DeltaType) && isValidKeyAndValue(result, ObjectClassKeyName))
            {
                var objclass = result[ObjectClassKeyName];
                if (objclass is ObjectClass)
                {
                    syncbld.ObjectClass = objclass as ObjectClass;
                }
                else if (objclass is String)
                {
                    syncbld.ObjectClass = new ObjectClass(objclass as String);
                }
                else
                {
                    throw new ArgumentException("Unrecognized ObjectClass in Sync result");
                }
            }
            else
            {
                throw new ArgumentException("Object is missing in Sync result");
            }

            return(_handler.Handle(syncbld.Build()));
        }