07 March 2011

Hello,

Some days ago, i was requested to add rules to our project, the rule have some rules: must be configured (outside of code), provide the  rule part of the current xml implementation, readable and of course, we dont have such time to do it, we have zero time.

First i decide to have this ability part of our flow xml data.

Rule definition lang should bring the ability to read/change/maintain/update/ add new functionllity in future/ etc the rule.

So, Rule should be xml or something closer.

In order to have within a xml document (my old and pretty xml files) a rule definition language, i had some ideas how to do it,

1. CDATA
2. Regular Expression
3. Json

I decided on json.

Why ?

CData, complex to read and maintains.

Regular expression, hard to maintain/read, not everyone familiar with it (its a pity but this is the reality)

So, i decide  to walk on Json,

Using json.net, it was very simple, just having xml with a json string, readable, simple and maintainable,

Before code, the rule should calculate date 30 days ago and 15 days ahead (this may change in production).

Let's code :

this is the json.net impl class


    [JsonObject(MemberSerialization.OptOut)]
    public class DatePlaceHolderDataItem : BasePlaceHolderDataItem
    {
        [JsonProperty]
        public Format Format { get; set; }


        [JsonProperty(PropertyName = "CalcBy")]
        public DateCalculation DateCalculation
        {
            get;
            set;
        }
    }


    [JsonObject(MemberSerialization.OptOut)]
    public class DateCalculateBy
    {
        [JsonProperty]
        public int Value { get; set; }
    }


....

i have defined new class BasePlaceHolderDataItem as follow :


public class BasePlaceHolderDataItem 
    {
        protected virtual Formatting SerializeFormattingType
        {
            get { return Formatting.None; }
        }


        public virtual string Serialize()
        {
            try
            {
                return JsonConvert.SerializeObject(this, SerializeFormattingType);
            }
            catch(Exception  exception)
            {
                throw new PlaceHolderException("Failed to Serialize place holder object.", exception);
            }
        }


        public static T Deserialize(string jsonDataItem)
        {
            if (string.IsNullOrEmpty(jsonDataItem))
            {
                return default(T);
            }


            try
            {
                return JsonConvert.DeserializeObject(jsonDataItem);
            }
            catch (Exception exception)
            {
                throw new PlaceHolderException( string.Format("Failed to Deserialize place holder string : {0}.", jsonDataItem), exception);
            }
        }
    }


lets examine the impl,

the FromPlaceHolder  identify place holder are parse it using the Deserialize method, invoke the ParsePlaceHolderByDataItem,  parse the object itself, simple and readable.

        public string FromPlaceHolder(string placeHolderData)

        {
            // DatePlaceHolderDataItem
            if (placeHolderData.StartsWith("{"))
            {
                DatePlaceHolderDataItem datePlaceHolderDataItem = DatePlaceHolderDataItem.Deserialize(placeHolderData);
               
                if( datePlaceHolderDataItem != null )
                {
                    return ParsePlaceHolderByDataItem(datePlaceHolderDataItem);
                }                
            }


            return ParsePlaceHolderByFormat(placeHolderData);            
        }


        private string ParsePlaceHolderByDataItem(DatePlaceHolderDataItem datePlaceHolderDataItem)
        {
            DateTime dateTime = DateTime.Now;


            if( datePlaceHolderDataItem.DateCalculation != null )
            {
                if( datePlaceHolderDataItem.DateCalculation.Year != null )
                {
                    dateTime = dateTime.AddYears(datePlaceHolderDataItem.DateCalculation.Year.Value);
                }
            }


            if (datePlaceHolderDataItem.DateCalculation != null)
            {
                if (datePlaceHolderDataItem.DateCalculation.Month != null)
                {
                    dateTime = dateTime.AddMonths(datePlaceHolderDataItem.DateCalculation.Month.Value);
                }
            }


            if (datePlaceHolderDataItem.DateCalculation != null)
            {
                if (datePlaceHolderDataItem.DateCalculation.Day != null)
                {
                    dateTime = dateTime.AddDays(datePlaceHolderDataItem.DateCalculation.Day.Value);
                }
            }


            if (datePlaceHolderDataItem.DateCalculation != null)
            {
                if (datePlaceHolderDataItem.DateCalculation.Hour != null)
                {
                   dateTime = dateTime.AddHours(datePlaceHolderDataItem.DateCalculation.Hour.Value);
                }
            }


            if (datePlaceHolderDataItem.DateCalculation != null)
            {
                if (datePlaceHolderDataItem.DateCalculation.Minute != null)
                {
                    dateTime = dateTime.AddMinutes(datePlaceHolderDataItem.DateCalculation.Minute.Value);
                }
            }


            if (datePlaceHolderDataItem.DateCalculation != null)
            {
                if (datePlaceHolderDataItem.DateCalculation.Second != null)
                {
                    dateTime = dateTime.AddSeconds(datePlaceHolderDataItem.DateCalculation.Second.Value);
                }
            }


            if( datePlaceHolderDataItem.Format != null && !string.IsNullOrEmpty(datePlaceHolderDataItem.Format.value) )
            {
                return dateTime.ToString(datePlaceHolderDataItem.Format.value);
            }


            return dateTime.ToString();
        }


using the Object oriented and json (also xml) capability give the developer to design & create generic platform of rule language.

Lets look on the xml :



  command.exe file.xml -s{current_data_time:{"Format":{"value":"MM/dd/yyyy"},"CalcBy":{"Day":{"Value":-30}}}} -e{current_data_time:{"Format":{"value":"MM/dd/yyyy"},"CalcBy":{"Day":{"Value":15}}}}}



Enjoy.

No comments: