using System;
using System.Collections.Generic;
namespace FunWithInsurance
{
/// <summary>
/// Basically the manager or component is responsible for
/// implementation of security authorization, logging auditing
/// and upmost behavior verbs, ie. Create(), Save(), Get(), Delete(), CreateQuote()
/// I'm using a Manager here for my example.
/// The context is your meta data used to maintain a healthy application
/// </summary>
public class PolicyManager
{
public PolicyManager() { }
#region Create Policy
public IPolicy CreatePolicy(IPolicy policy, out Context context)
{
if (!this.HasRights(context, ActionType.Create))
{
Log.SecurityLog(policy, context, ActionType.Create);
throw new Exception("This action is not allowed.");
}
// Before Event Handling:
// Now is a good time to subscribe or fire to necessary events
// that happen BEFORE you hand off a policy to Create
// ex. Notifications and Messaging, or Invalid State
try
{
// Get the processor
PolicyProcessor policyProcessor = ProcessorFactory.Create(policy);
//Call the processor
IPolicy policy = policyProcessor.ProcessCreate(policy, context);
}
catch (Exception exc)
{
//log exception, object, context, and verb
Log.ExceptionLog(exc, policy, context, Action.Create);
}
// Post Event Handling
// Now is a good time to subscribe or fire to necessary events
// that happen AFTER a policy get's processed from Create
// ex. Notifications and Messaging, or Invalid State
//Since this type of information is extremely sensitive we log all actions
Log.Entry(policy, context, ActionType.Create);
// Return entity
return policy;
}
#endregion
#region Save Policy
/// <summary>
/// Notice there is no actual implementation here. I'm really just here to keep things moving around
/// and ensure that the health of my application is in order.
/// Think of a manager in a store. The manager really only walks around and handles exceptional cases.
/// The manager does not actually do any work, other than
/// 1. Overrides (Security and Auth - based on context)
/// 2. Angry Customers (thrown Exceptions)
/// 3. Handles Manager On Duty (MOD) Calls (Event Management)
/// 4. opens and Locks the Store (The manager object should be the entry point for all things in your complex application)
/// </summary>
/// <param name="policy">entity</param>
/// <param name="context">context can enclose security authorization and anything</param>
/// <returns>IPolicy as a typed Policy</returns>
public IPolicy SavePolicy(IPolicy policy, out Context context)
{
if (!this.HasRights(context, ActionType.Save))
{
Audit.SecurityLog(policy, context, ActionType.Save);
throw new Exception("This action is not allowed.");
}
// Before Event Handling:
// Now is a good time to subscribe or fire to necessary events
// that happen BEFORE you hand off a policy to Create
// ex. Notifications and Messaging, or Invalid State
try
{
// Get the processor
PolicyProcessor policyProcessor = ProcessorFactory.Create(policy, context);
//Call the processor
IPolicy policy = policyProcessor.ProcessSave();
}
catch (Exception exc)
{
//log exception, object, context, and verb
Log.ExceptionLog(exc, policy, context, Action.Save);
}
// Post Event Handling
// Now is a good time to subscribe or fire to necessary events
// that happen AFTER a policy get's processed from Create
// ex. Notifications and Messaging, or Invalid State
//Since this type of information is extremely sensitive we log all actions
Log.Entry(policy, c, ActionType.Save);
// Return entity
return policy;
}
#endregion
#region ProcessorFactory
public class ProcessorFactory
{
public static PolicyProcessor Create(IPolicy policy, Context context)
{
// use a property in Policy to create a new policy processor to use.
// You can get fancy by using reflection and Activator.CreateInstance, to determine this as well.
// ensure that you pass in both the policy and context to processor.
}
}
#endregion
}
#region Policy Processors
public class PolicyProcessor
{
public IPolicy ProcessCreate();
public IPolicy ProcessSave();
public IPolicy ProcessDelete();
public IPolicy ProcessGetBy();
}
#region TermLifeProcessor
/// <summary>
/// this process is responsible for the actual implementations to for my particular policy.
/// </summary>
public class TermLifeProcessor : PolicyProcessor
{
private IPolicy policy;
private Context context;
/// <summary>
/// The factory is responsible for the creation of the Processor, and assigning the policy and context.
/// </summary>
/// <param name="policy"></param>
/// <param name="context"></param>
TermLifeProcessor(IPolicy policy, Context context)
{
this.policy = policy;
this.context = context;
}
/// <summary>
/// All the real magic is done in here
/// this process is responsible for these steps to save my policy.
/// 1. it has to validate and save the terms
/// 2. it has to validate and save the conditions
/// 3. it has to validate and save my policyholder info,
/// 4. which would in turn call the policyholdermanager//
/// 5. which would validate and save my policyholder rider info, you get the idea.
/// </summary>
/// <param name="policy"></param>
/// <param name="context"></param>
/// <returns></returns>
public IPolicy ProcessSave()
{
if (IsEntityValid(policy))
{
if (context.HasTransaction
&& context.TransactionManager != null
&& context.TransactionManager.Isopen)
{
DataRepository.PolicyProvider.Save(context.TransactionManager, policy);
DataRepository.TermsProvider.Save(context.TransactionManager, policy.TermsCollection);
DataRepository.ConditionsProvider.Save(context.TransactionManager, policy.ConditionsCollection);
}
// or if modeled correctly, you can just call Deep save
}
}
public IPolicy ProcessCreate()
{
//same body type as ProcessSave()
}
/// <summary>
/// check the entity, along with the children this processor is responsible for.
/// for this particular product
/// </summary>
/// <returns></returns>
public bool IsEntityValid()
{
bool isValid = true;
// You can do your type checking
if (!(policy is TermLifePolicy))
{
isValid = false;
}
if(policy.Coverage > Policy.MaxCoverage)
{
this.context.Messages.Add(new Message("The coverage amount is invalid.", MessageType.ProcessorError));
isValid = false;
}
if (policy.Term.TermLength > Policy.Term.MaxTermLength)
{
this.context.Messages.Add(new Message("The term length is invalid, it can not exceed 30 years.", MessageType.ProcessorError));
isValid = false;
}
return isValid;
}
}
#endregion
public class WholeLifeProcessor : PolicyProcessor
{
// All the work with the entities goes in here.
// same as above, just with different business rules
}
#endregion
#region BLL Context and Stuff
public enum ActionType
{
Create,
Save,
Process,
Read,
Get,
CreateQuote
}
/// <summary>
/// This can be considered the Meta-Data Class
/// can contain current user, roles, groups, permissions
/// pages/forms affected
/// AuditTrail things like that.
/// transaction enlistment
/// Warnings and Errors that can be sent back to the UI
/// </summary>
public class Context
{
public SecurityPrincipal User
{
get { }
}
/// <summary>
/// Able to wrap the transaction manager for enlistment.
/// </summary>
public DataAccessLayer.TransactionManager TransactionManager
{
get { }
set { }
}
// messages that can be delivered back to the UI, for showing
public List<Message> MessageList;
}
#endregion
#region Business Entity classes
public class Person : Entities.Person
{
string Name;
string Age;
string Relationship;
}
public class PolicyHolder
{
public Person Assignee;
List<Person> Riders;
List<Person> Benificiary;
}
public interface IPolicy
{
public virtual Entities.TermCollection Terms
{ get; set; }
public virtual Entities.ConditionCollection Conditions
{ get; set; }
}
public class TermLifePolicy : Entities.Policy, IPolicy
{
public TermCollection Terms
{
get {
if (terms == null)
terms = TermLifeTerm.GetTermsByPolicyId(this.PolicyId, this.Context);
return terms;
}
}
public ConditionCollection Conditions
{
get
{
if (conditions == null)
conditions = TermLifeCondition.GetConditionByPolicyId(this.PolicyId, this.Context);
}
}
}
public class WholeLifePolicy : Entities.Policy
{
public TermCollection Terms
{
get
{
if (terms == null)
terms = WholeLifeTerm.GetTermsByPolicyId(this.PolicyId, this.Context);
return terms;
}
}
public ConditionCollection Conditions
{
get
{
if (conditions == null)
conditions = WholeLifeCondition.GetConditionByPolicyId(this.PolicyId, this.Context);
}
}
}
/// <summary>
/// Inheritance for Type Matching Only,
/// No Actual Behavior implementation here
/// favor using compositon, HAS-A relationships to fullfil
/// Whole Life Term specific implementation needs
/// </summary>
public class WholeLifeTerm : Terms
{
#region Create Mapping Methods
/// <summary>
/// If you do not have a static factory creational pattern in the DAL,
/// like i posted in the forums
/// http://forum.codesmithtools.com/default.aspx?f=19&p=1&m=8534
/// Posted 11/7/2005 7:52 PM (GMT -6)
/// (about halfway down the page)
///
/// Then you will have to map your entities to your Decorator Objects.
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
public static WholeLifeTerm Create(Entities.Term t)
{
WholeLifeTerm w = new WholeLifeTerm();
this.termID = t.TermId;
this.specificTerm = GetSpecificTermFromSomewhere();
return w;
}
public static TermCollection Create (Entities.TermCollection terms)
{
TermCollection tc = new TermCollection();
foreach(Term t in terms)
c.Add(Create(t));
return tc;
}
#endregion
/// <summary>
/// My Terms Data Access
/// </summary>
/// <param name="policyId"></param>
/// <returns></returns>
public static Entities.TermsCollection GetTermsByPolicy(int policyId)
{
// having to map, because the NetTiers.DAL is being used as is out of the box.
// if we are creating and using inheritance for Type Matching, then you'll have to map to your business type
// otherwise, if you use a creational factory in the DAL, then you can have those types be created when you
// specify what type to create.
// More Info on creational factory pattern: See the summary in the Create Method above.
return Create(DataRepository.TermsProvider.GetTermsByPolicyId(policyId));
}
public MySpecificTerm SpecificTerm
{
get { }
set { }
}
}
#region More Terms and Conditions -
/// <summary>
/// Inheritance for Type Matching Only,
/// No Actual Behavior implementation here
/// favor using compositon, HAS-A relationships to
/// fullfil Whole Life Condition specific implementation needs
///
/// SEE IMPLEMENTATION ABOVE as it's the same but now dealing with Conditions.
/// </summary>
public class WholeLifeCondition : Conditions
{
public MySpecificCondition SpecificCondition
{
get { }
set { }
}
}
/// <summary>
/// Inheritance for Type Matching Only,
/// No Actual Behavior implementation here
/// favor using compositon, HAS-A relationships to fullfil Term Life Term specific implementation needs
///
/// SEE IMPLEMENTATION ABOVE as it's the same but now dealing with Conditions.
/// </summary>
public class TermLifeTerm : Term
{
public MySpecificTerm SpecificTerm
{
get { }
set { }
}
}
/// <summary>
/// Inheritance for Type Matching Only,
/// No Actual Behavior Implementation Here
/// favor using compositon, HAS-A relationships to fullfil term-life specific implementation needs
///
/// SEE IMPLEMENTATION ABOVE as it's the same but now dealing with Conditions.
/// </summary>
public class TermLIfeCondition : Condition
{
public MySpecificCondition SpecificCondition
{
get { }
set { }
}
}
#endregion
/// <summary>
/// Basic Term, inherits from generated entity.
/// </summary>
public class Term : Entities.Term
{
}
/// <summary>
/// Basic Condition table, inherits from Entity.Condition
/// </summary>
public class Condition : Entities.Condition
{
}
#endregion
}