January 29, 2013 | Kristian Birk Thim

Changes to: Activity.CopyValues.cs
- Extended the AttributeValue class to include more logic specific to it.
- Created ConditionalAttributeValue. A AttributeValue class which includes conditional properties (Inherits from AttributeValue)
- Created AttributeValueCollection which includes some of the processing logic specific to a collection of AttributeValues.
- Re-Wrote parts of the main code to incorporate the new classes.
master
mihtnick_cp 2013-01-30 09:42:28 -08:00
parent 579513ce7d
commit 595473405b
9 changed files with 461 additions and 70 deletions

Binary file not shown.

View File

@ -3,6 +3,11 @@
// January 22, 2013 | Soren Granfeldt
// - added function to convert different types/values
// before comparison.
// January 29, 2013 | Kristian Birk Thim
// - Extended the AttributeValue class to include more logic specific to it.
// - Created ConditionalAttributeValue. A AttributeValue class which includes conditional properties (Inherits from AttributeValue)
// - Created AttributeValueCollection which includes some of the processing logic specific to a collection of AttributeValues.
// - Re-Wrote parts of the main code to incorporate the new classes.
using System;
using System.Collections;
@ -28,20 +33,6 @@ namespace Granfeldt.FIM.ActivityLibrary
public partial class CopyValuesActivity : SequenceActivity
{
public class AttributeValue
{
public string SourceAttributeName { get; set; }
public object SourceAttributeValue { get; set; }
public string TargetAttributeName { get; set; }
public object TargetAttributeValue { get; set; }
public bool ShouldResolve = false;
public string ConditionAttributeName { get; set; }
public bool ConditionAttributeValue { get; set; }
}
#region Properties
public static DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(CopyValuesActivity));
@ -181,7 +172,7 @@ namespace Granfeldt.FIM.ActivityLibrary
AttributeValue ResolvedAttributeValue;
List<string> selectionAttributes = new List<string>();
List<AttributeValue> attrValues = new List<AttributeValue>();
AttributeValueCollection attrValues = new AttributeValueCollection();
public CopyValuesActivity()
{
@ -204,7 +195,16 @@ namespace Granfeldt.FIM.ActivityLibrary
Debugging.Log("Add selection attribute", se);
selectionAttributes.Add(se);
}
attrValues.Add(new AttributeValue { ShouldResolve = s[0].Trim().Contains("[//"), SourceAttributeName = s[0].Trim(), ConditionAttributeName = s[1].Trim(), TargetAttributeName = s[2].Trim() });
if (s[1].Trim() == "")
{
//Non-conditional AttributeValue
attrValues.Add(new AttributeValue(s[0].Trim(), s[2].Trim()));
}
else
{
//Conditional AttributeValue
attrValues.Add(new ConditionalAttributeValue(s[0].Trim(), s[2].Trim(), s[1].Trim(), this.UpdateOnTrue));
}
}
}
}
@ -240,14 +240,14 @@ namespace Granfeldt.FIM.ActivityLibrary
// the target attribute value (if present)
Debugging.Log("Missing value or invalid XPath reference", this.ResolveSourceGrammar.GrammarExpression);
ResolvedAttributeValue.SourceAttributeValue = null;
ResolvedAttributeValue.ShouldResolve = false;
//ResolvedAttributeValue.ShouldResolve = false;
}
private void FetchResolvedGrammar_ExecuteCode(object sender, EventArgs e)
{
Debugging.Log("Resolved", this.ResolvedSourceExpression);
ResolvedAttributeValue.SourceAttributeValue = this.ResolvedSourceExpression;
ResolvedAttributeValue.ShouldResolve = false;
//ResolvedAttributeValue.ShouldResolve = false; //IsResolved is set automatically
}
private void ShouldDoLookup_Condition(object sender, ConditionalEventArgs e)
@ -325,59 +325,10 @@ namespace Granfeldt.FIM.ActivityLibrary
try
{
List<UpdateRequestParameter> updateParameters = new List<UpdateRequestParameter>();
foreach (AttributeValue val in attrValues)
{
val.TargetAttributeValue = this.ReadTarget.Resource[val.TargetAttributeName] != null ? this.ReadTarget.Resource[val.TargetAttributeName] : null;
Debugging.Log(val.TargetAttributeName, val.TargetAttributeValue);
if (!(string.IsNullOrEmpty(val.ConditionAttributeName)))
{
val.ConditionAttributeValue = this.ReadTarget.Resource[val.ConditionAttributeName] != null ? (bool)this.ReadTarget.Resource[val.ConditionAttributeName] : true;
}
else
{
val.ConditionAttributeValue = true;
}
//Gets all non matching AttributeValues in AttrValues.
updateParameters = attrValues.Changes;
// we need the original (non-converted) value if we are doing a removal as we must specify the original value (even a local date/time)
object originalTargetValue = val.TargetAttributeValue;
val.TargetAttributeValue = FIMAttributeUtilities.FormatValue(val.TargetAttributeValue);
val.SourceAttributeValue = FIMAttributeUtilities.FormatValue(val.SourceAttributeValue);
if (FIMAttributeUtilities.ValuesAreDifferent(val.SourceAttributeValue, val.TargetAttributeValue))
{
if (val.SourceAttributeValue == null)
{
// we are in a delete state
if (val.ConditionAttributeValue == this.UpdateOnTrue)
{
Debugging.Log(string.Format("Deleting value '{1}' from {0}", val.TargetAttributeName, val.TargetAttributeValue == null ? "(null)" : val.TargetAttributeValue));
updateParameters.Add(new UpdateRequestParameter(val.TargetAttributeName, UpdateMode.Remove, originalTargetValue));
}
else
{
Debugging.Log("Condition does not allow deleting", val.TargetAttributeName);
}
}
else
{
// we are in an update state
if (val.ConditionAttributeValue == this.UpdateOnTrue)
{
Debugging.Log(string.Format("Updating {0} from '{1}' to '{2}'", val.TargetAttributeName, val.TargetAttributeValue == null ? "(null)" : val.TargetAttributeValue, val.SourceAttributeValue));
updateParameters.Add(new UpdateRequestParameter(val.TargetAttributeName, UpdateMode.Modify, val.SourceAttributeValue));
}
else
{
Debugging.Log("Condition does not allow updating", val.TargetAttributeName);
}
}
}
else
{
Debugging.Log(string.Format("No need to update {0}. Value is already {1}", val.TargetAttributeName, val.TargetAttributeValue == null ? "(null)" : val.TargetAttributeValue));
}
}
// if we have added any update parameters this means that there are changes
// so we prepare the update activtiy with relevant information and
// set e.Result to true to ensure that the Update activity is called
@ -426,5 +377,11 @@ namespace Granfeldt.FIM.ActivityLibrary
{
Debugging.Log("Error", UpdateTarget.ExecutionResult);
}
private void SetTargetResource_ExecuteCode(object sender, EventArgs e)
{
//Sets the TargetResource on the attValues collection
attrValues.TargetResource = this.ReadTarget.Resource;
}
}
}

View File

@ -48,6 +48,7 @@ namespace Granfeldt.FIM.ActivityLibrary
this.YesUpdateTarget = new System.Workflow.Activities.IfElseBranchActivity();
this.faultHandlerActivity1 = new System.Workflow.ComponentModel.FaultHandlerActivity();
this.ShouldUpdateTargetObject = new System.Workflow.Activities.IfElseActivity();
this.SetTargetOnAttributeValueCollection = new System.Workflow.Activities.CodeActivity();
this.ReadTarget = new Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity();
this.ExtractTargetObjectID = new System.Workflow.Activities.CodeActivity();
this.FindTargetResource = new Granfeldt.FIM.ActivityLibrary.FindResourcesActivity();
@ -136,6 +137,11 @@ namespace Granfeldt.FIM.ActivityLibrary
this.ShouldUpdateTargetObject.Activities.Add(this.faultHandlersActivity3);
this.ShouldUpdateTargetObject.Name = "ShouldUpdateTargetObject";
//
// SetTargetOnAttributeValueCollection
//
this.SetTargetOnAttributeValueCollection.Name = "SetTargetOnAttributeValueCollection";
this.SetTargetOnAttributeValueCollection.ExecuteCode += new System.EventHandler(this.SetTargetResource_ExecuteCode);
//
// ReadTarget
//
this.ReadTarget.ActorId = new System.Guid("00000000-0000-0000-0000-000000000000");
@ -204,6 +210,7 @@ namespace Granfeldt.FIM.ActivityLibrary
// UpdateSequence
//
this.UpdateSequence.Activities.Add(this.ReadTarget);
this.UpdateSequence.Activities.Add(this.SetTargetOnAttributeValueCollection);
this.UpdateSequence.Activities.Add(this.ShouldUpdateTargetObject);
this.UpdateSequence.Name = "UpdateSequence";
//
@ -272,6 +279,8 @@ namespace Granfeldt.FIM.ActivityLibrary
#endregion
private CodeActivity SetTargetOnAttributeValueCollection;
private CodeActivity codeActivity1;
private FaultHandlerActivity faultHandlerActivity2;
@ -390,6 +399,8 @@ namespace Granfeldt.FIM.ActivityLibrary

View File

@ -0,0 +1,186 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.ResourceManagement.WebServices.WSResourceManagement;
namespace Granfeldt.FIM.ActivityLibrary
{
public class AttributeValue
{
//Constructors
/// <summary>
/// Creates a new instance of the object type AttributeValue.
/// </summary>
public AttributeValue()
{
this.IsResolved = false;
}
/// <summary>
/// Creates a new instance of the object type AttributeValue, and sets source and target attribute name.
/// </summary>
/// <param name="sourceAttributeName">Name of the source attribute.</param>
/// <param name="targetAttributeName">Name of the target attribute.</param>
public AttributeValue(string sourceAttributeName, string targetAttributeName)
{
this.SourceAttributeName = sourceAttributeName;
this.TargetAttributeName = targetAttributeName;
this.IsResolved = false;
}
//Fields
private object _sourceAttributeValue;
//Properties
public string SourceAttributeName { get; set; }
public object SourceAttributeValue
{
get
{
return this._sourceAttributeValue;
}
set
{
this._sourceAttributeValue = value;
this.IsResolved = true;
}
}
public string TargetAttributeName { get; set; }
public object TargetAttributeValue { get; set; }
public bool IsDelete { get; private set; }
/// <summary>
/// Indicates if the SourceAttributeName have been resolved.
/// This is set when SourceAttributeValue is set.
/// </summary>
public bool IsResolved { get; private set; }
/// <summary>
/// Tells if the SourceAttributeValue should be resolved from SourceAttributeName.
/// It is decided by testing if the SourceAttributeName contains a resolveable string.
/// </summary>
public bool ShouldResolve
{
get
{
if (this.IsResolved)
{
return false;
}
else
{
if (this.SourceAttributeName != null)
return this.SourceAttributeName.Trim().Contains("[//");
else
return false;
}
}
}
#region Methods
/// <summary>
/// Returns this AttributeValue as an UpdateRequestParameter used for updating resources in FIM.
/// </summary>
/// <param name="objectId">ObjectID of the resource being updated.</param>
/// <param name="isDelete">Tells the method what type of update to return.
/// If isDelete is true a UpdateMode is set to: Remove.
/// </param>
/// <returns></returns>
public UpdateRequestParameter ToUpdateRequestParameter(Guid objectId,bool isDelete)
{
if (!isDelete)
return new UpdateRequestParameter(objectId, this.TargetAttributeName, UpdateMode.Modify, FIMAttributeUtilities.FormatValue(this.SourceAttributeValue), false);
else
{
return new UpdateRequestParameter(objectId, this.TargetAttributeName, UpdateMode.Remove, this.TargetAttributeValue, false);
}
}
/// <summary>
/// Returns this AttributeValue as an UpdateRequestParameter used for updating resources in FIM, without specifying which object to update.
/// </summary>
/// <param name="isDelete">Tells the method what type of update to return.
/// If isDelete is true a UpdateMode is set to: Remove.</param>
/// <returns></returns>
public UpdateRequestParameter ToUpdateRequestParameter(bool isDelete)
{
if (!isDelete)
return new UpdateRequestParameter(this.TargetAttributeName, UpdateMode.Modify, FIMAttributeUtilities.FormatValue(this.SourceAttributeValue), false);
else
{
return new UpdateRequestParameter(this.TargetAttributeName, UpdateMode.Remove, this.TargetAttributeValue, false);
}
}
/// <summary>
/// Compares the source value with the supplied readValue parameter.
/// Also sets IsDelete to true or false
/// </summary>
/// <param name="readValue">A value to compare with the SourceValue.</param>
/// <returns></returns>
public virtual bool ShouldUpdate(object readValue)
{
// we need the original (non-converted) value if we are doing a removal as we must specify the original value (even a local date/time)
// object originalTargetValue = this.TargetAttributeValue;
object target = FIMAttributeUtilities.FormatValue(readValue);
object source = FIMAttributeUtilities.FormatValue(this.SourceAttributeValue);
return getShouldUpdate(target, source);
}
/// <summary>
/// Compares the Target attribute value with the existing source attribute value. If the source attribute value is not set,
/// it will be compared on as a null value.
/// </summary>
/// <returns>Result of compare</returns>
public virtual bool ShouldUpdate()
{
object target = FIMAttributeUtilities.FormatValue(this.TargetAttributeValue);
object source = FIMAttributeUtilities.FormatValue(this.SourceAttributeValue);
Debugging.Log(String.Format("Comparing source: {0} and target: {1}, containing the values: {2} / {3}", this.SourceAttributeName, this.TargetAttributeName, this.SourceAttributeValue, this.TargetAttributeValue));
bool result = getShouldUpdate(target, source);
Debugging.Log(String.Format("Comparison resulted in: {0}",result));
return result;
}
/// <summary>
/// Private method for comparing Source and Target attributes
/// </summary>
/// <param name="target">Taget value</param>
/// <param name="source">Source value</param>
/// <returns>Whether or not the target attribute should be updated.</returns>
private bool getShouldUpdate(object target, object source)
{
if (FIMAttributeUtilities.ValuesAreDifferent(source, target))
{
if (source == null)
{
// we are in a delete state
Debugging.Log(string.Format("Deleting value '{1}' from {0}", this.TargetAttributeName, target == null ? "(null)" : target));
this.IsDelete = true;
}
else
{
// we are in an update state
Debugging.Log(string.Format("Updating {0} from '{1}' to '{2}'", this.TargetAttributeName, target == null ? "(null)" : target, source));
this.IsDelete = false;
}
return true;
}
else
{
Debugging.Log(string.Format("No need to update {0}. Value is already {1}", this.TargetAttributeName, this.TargetAttributeValue == null ? "(null)" : this.TargetAttributeValue));
this.IsDelete = false;
return false;
}
}
/// <summary>
/// Sets the TargetAttributeValue on this AttributeValue based on the it's current TargetAttributeName.
/// </summary>
/// <param name="resource">the ResourceType object to pull the attribute value from.</param>
internal virtual void SetValues(ResourceType resource)
{
TargetAttributeValue = resource[this.TargetAttributeName] != null ? resource[this.TargetAttributeName] : null;
Debugging.Log(this.TargetAttributeName, this.TargetAttributeValue);
}
#endregion
}
}

View File

@ -0,0 +1,131 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.ResourceManagement.WebServices.WSResourceManagement;
namespace Granfeldt.FIM.ActivityLibrary
{
public class AttributeValueCollection : ICollection<AttributeValue>
{
//Constructors
/// <summary>
/// Creates a new instance of AttributeValueCollection.
/// </summary>
public AttributeValueCollection()
{
this._attributeValues = new List<AttributeValue>();
}
/// <summary>
/// Creates a new instance of AttributeValueCollection that takes the ObjectID of the target resource.
/// </summary>
/// <param name="targetObjectID">ObjectID of the target resource</param>
public AttributeValueCollection(Guid targetObjectID)
{
this.TargetObjectID = targetObjectID;
this._attributeValues = new List<AttributeValue>();
}
//Fields
/// <summary>
/// List of all the AttributeValue objects in the collection.
/// </summary>
private List<AttributeValue> _attributeValues;
/// <summary>
/// Target resource that needs to be updates.
/// </summary>
private ResourceType _targetResource;
//Properties
public Guid TargetObjectID { get; set; }
public ResourceType TargetResource
{
get { return _targetResource; }
set
{
_targetResource = value;
PopulateAttributeValues();
}
}
/// <summary>
/// Gets all the AttributeValues in the collection, which contains differences between the source and the target value
/// </summary>
/// <returns>All changes in the collection to send to target.</returns>
public List<UpdateRequestParameter> Changes
{
get
{
List<UpdateRequestParameter> changes = new List<UpdateRequestParameter>();
foreach (AttributeValue a in _attributeValues)
{
Debugging.Log(a.TargetAttributeName, a.TargetAttributeValue);
if (a.ShouldUpdate())
{
changes.Add(a.ToUpdateRequestParameter(this.TargetObjectID, a.IsDelete));
}
}
return changes;
}
}
#region Methods
/// <summary>
/// Sets attribute values on all AttributeValue objects in the collection.
/// </summary>
private void PopulateAttributeValues()
{
foreach (AttributeValue val in _attributeValues)
{
val.SetValues(_targetResource);
}
}
#region ICollection implementation
public void Add(AttributeValue item)
{
this._attributeValues.Add(item);
}
public void Clear()
{
this._attributeValues.Clear();
}
public bool Contains(AttributeValue item)
{
return this._attributeValues.Contains(item);
}
public void CopyTo(AttributeValue[] array, int arrayIndex)
{
this._attributeValues.CopyTo(array, arrayIndex);
}
public int Count
{
get { return this._attributeValues.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(AttributeValue item)
{
return this._attributeValues.Remove(item);
}
public IEnumerator<AttributeValue> GetEnumerator()
{
return this._attributeValues.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
#endregion
}
}

View File

@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.ResourceManagement.WebServices.WSResourceManagement;
namespace Granfeldt.FIM.ActivityLibrary
{
public class ConditionalAttributeValue : AttributeValue
{
//Constructors
public ConditionalAttributeValue(string conditionAttributeName)
{
this.ConditionAttributeName = conditionAttributeName;
}
public ConditionalAttributeValue(string sourceAttributeName, string targetAttributeName, string conditionAttributeName)
{
this.ConditionAttributeName = conditionAttributeName;
this.SourceAttributeName = sourceAttributeName;
this.TargetAttributeName = targetAttributeName;
}
public ConditionalAttributeValue(string sourceAttributeName, string targetAttributeName, string conditionAttributeName, bool updateOnConditionTrue)
{
this.ConditionAttributeName = conditionAttributeName;
this.UpdateOnTrue = updateOnConditionTrue;
this.SourceAttributeName = sourceAttributeName;
this.TargetAttributeName = targetAttributeName;
}
//Properties
public string ConditionAttributeName { get; set; }
public bool ConditionAttributeValue { get; private set; }
public bool UpdateOnTrue { get; set; }
/// <summary>
/// Compares the Target attribute value with the existing source attribute value. If the source attribute value is not set,
/// it will be compared on as a null value.
/// </summary>
/// <returns>Result of the comparison.</returns>
public override bool ShouldUpdate()
{
if (conditionsSatisfied())
{
return base.ShouldUpdate();
}
else
{
Debugging.Log(String.Format("Conditions not met. Because {0} has the value: {1}.",this.ConditionAttributeName,this.ConditionAttributeValue));
return false;
}
}
/// <summary>
/// Sets Source and Target values as well as conditional values.
/// </summary>
/// <param name="resource">resource object of the target to be updated.</param>
internal override void SetValues(ResourceType resource)
{
base.SetValues(resource);
this.SetConditionValue(resource);
}
/// <summary>
/// Private methods that determines if the conditions are met to allow the target to be updated.
/// </summary>
/// <returns>If conditions are met, it will return true, otherwise false.</returns>
private bool conditionsSatisfied()
{
if (UpdateOnTrue)
{
if (ConditionAttributeValue)
{
//True and True is True
return true;
}
else
{
return false;
}
}
else
{
if (!ConditionAttributeValue)
{
//False and False is true
return true;
}
else
{
return false;
}
}
}
/// <summary>
/// Sets the ConditionAttributeValue, based on ConditionAttributeName and <paramref name="resource"/>.
/// </summary>
/// <param name="resource"></param>
private void SetConditionValue(ResourceType resource)
{
this.ConditionAttributeValue = resource[this.ConditionAttributeName] != null ? (bool)resource[this.ConditionAttributeName] : false;
Debugging.Log(String.Format("Condition set to: {0}", this.ConditionAttributeValue));
}
}
}

View File

@ -102,6 +102,9 @@
<DependentUpon>Activity.LookupAttributeValue.cs</DependentUpon>
</Compile>
<Compile Include="Activity.LookupAttributeValue\Activity.LookupAttributeValue.SettingsPart.cs" />
<Compile Include="Base.Classes\AttributeValue\AttributeValue.cs" />
<Compile Include="Base.Classes\AttributeValue\AttributeValueCollection.cs" />
<Compile Include="Base.Classes\AttributeValue\ConditionalAttributeValue.cs" />
<Compile Include="Base.Classes\Base.ActivitySettings.cs" />
<Compile Include="Base.Classes\Base.HelperClasses.cs" />
<Compile Include="Activity.CodeRun\Activity.CodeRun.SettingsPart.cs" />

View File

@ -30,4 +30,4 @@ using System.Runtime.InteropServices;
//NOTE: When updating the namespaces in the project please add new or update existing the XmlnsDefinitionAttribute
//You can add additional attributes in order to map any additional namespaces you have in the project
//[assembly: System.Workflow.ComponentModel.Serialization.XmlnsDefinition("http://schemas.com/Granfeldt.FIM.ActivityLibrary", "Granfeldt.FIM.ActivityLibrary")]
[assembly: AssemblyFileVersionAttribute("1.3.0.0")]
[assembly: AssemblyFileVersionAttribute("1.4.0.0")]