Life Management System Part 1

Finally done with Thanksgiving. I've always said that you can only take so much family before someone has to be thrown out the window. Oh, and I know this should really be part 2 but I hate it when people have a part 1 that is all text and no code. It doesn't help you get a grasp of what they're doing. So even though I talked about the project before, I consider this part 1. However if you want to read my ramblings on the project, you can do so here.

As far as setup of the system, I'm using my utility library, HaterAide, and YABOV.  The use of HaterAide means that I'll have to change it slightly. It was originally designed for prototyping of a website but I'll have to end up modifying it to work with different types of applications. Past that the general layout of the system thus far is slightly different from what I thought it would be but it's currently this:

 

The system is divided into the following systems: IO, Processor, Services, Session, Settings, Tasks, and a core that controls everything. It's a little difficult to tell from the diagram which is which considering it doesn't show namespaces (also note that Tasks and Settings are not shown here). Anyway, the core is a singleton and holds the various systems, creates them, etc. The basic layout is as follows:

 

namespace Core
{
    public class CoreManager : Singleton<CoreManager>
    {
        protected CoreManager()
            : base()
        {

        }

        public void Setup()
        {
            LoadSettings();

            IOMappings = new ListMapping<IInput, IOutput>();
            ProcessorManager = new Processor.Manager();
            ServiceManager = new Services.Manager();
            SessionManager = new Session.Manager();
            TaskManager = new Tasks.Manager();
        }

        private void LoadSettings()
        {
            BusinessObjects.GlobalFunctions.Setup("CONNECTIONSTRINGFORSQL");
            System.Collections.Generic.List<Settings> SettingsList = BusinessObjects.Settings.LoadAll();
            for (int x = 0; x < SettingsList.Count; ++x)
            {
                if (SettingsList[x].Active)
                {
                    SettingsInfo = SettingsList[x];
                    return;
                }
            }

            SettingsInfo = new Settings();
            SettingsInfo.ProcessorDefaultClass = "Processor";
            SettingsInfo.SessionDefaultClass = "Session";
            SettingsInfo.ServicesDLL = "Services";
            SettingsInfo.Save();
        }

        public void Process()
        {
            foreach (IInput Input in IOMappings.Keys)
            {
                IValue Value = Input.GetInput();
                if (Value != null)
                {
                    Value = ProcessorManager.PreProcess(Input.GetInput());
                    System.Collections.Generic.List<IValue> OutputValues = ServiceManager.Process(Value);
                    ProcessorManager.PostProcess(OutputValues);
                    foreach (IOutput Output in IOMappings[Input])
                    {
                        Output.SetOutput(OutputValues);
                    }
                }
            }
        }

        public ListMapping<IInput, IOutput> IOMappings { get; protected set; }
        public Processor.Manager ProcessorManager { get; protected set; }
        public Services.Manager ServiceManager { get; protected set; }
        public Session.Manager SessionManager { get; protected set; }
        public Tasks.Manager TaskManager { get; protected set; }

        public Settings SettingsInfo { get; protected set; }
    }
}

 

The code above wont make much sense without the other systems but for now you can look at it in generalities. Initially the core is created, but note that the objects are not created at the same time. The reason for this is the way in which the Singleton class from my utility library works. The Singleton class creates the object and saves it in the base constructor. The base constructor is called after the class's constructor and since the ProcessorManager, ServiceManager, etc. will be using the core, we have to create the objects outside of the constructor. This leads us to the Setup function, which is pretty basic. However it calls the LoadSettings function, which in turn loads a class which is not even in the Core DLL. Instead it's using one of the classes from the BusinessObjects DLL. The BusinessObjects assembly currently looks like this:

 

Basically there are only two types here at present: Settings and User. I could break down settings into a list of type setting, which I may do, but at this time there isn't much of a point. Anyway, they both inherit from BaseObject. Thanks to how I created HaterAide, I can have the BaseObject type handle saving, deleting, loading, etc. On top of this, it contains a number of events that I can use to hook into the object for logging, etc. As such the individual objects don't need to do much other than set up the properties (which need to be virtual due to HaterAide) and any specific functions that it may need.

So back to the LoadSettings function. As I said, it loads the Settings objects and finds which one is active (current). It also calls a global function in the BusinessObjects DLL that simply starts up HaterAide:

        public static void Setup(string ConnectionString)
        {
            new Factory(typeof(IObject).Assembly, ConnectionString);
        }

 

IObject is simply the interface that the BaseObject class uses (which in turn has the ID, DateCreated, etc. properties). But anyway that's all that the LoadSettings function does. The rest of the Setup function simply creates the various subsystems (IO, Services, etc.). The IO class is simpy a ListMapping (another class from the utility library). Its only purpose is to hold each input item and map it to interested output items. The interface has to set these up. Although it shouldn't be in the core class as it turns out. Well not exactly anyway. Since, for now, I'm using a web interface it actually needs to be mapped at the session level. The core is static and thus constant even in a web app (more or less anyway). However I may have multiple people using this at once and so I need this to be mapped to an individual user's session. And since I'm using a web app there are actually other potential issues as well.

One of the main issues with a web app is the way that a page is created. When a request comes in, it creates a brand new Page object. It does this every time. The information is stored in the view state, which people think means that the object is still there in between requests. It's not. Request comes in, it creates a brand new Page object, loads info based on view state, does its thing, sends back a response, and destroys the Page object. Every time. That means that all of those buttons are new buttons, every time. So I can't even store the IO mappings across sessions. In reality the interface needs to set it up each and every time. So I still need to work on this aspect and figure out some way to automatically do this without writing tons of code in the interface portion.

The Processor, Session, and Services code is a bit simpler and more uniform actually. For example the Services manager code looks like this:

 

namespace Core.Services
{
    public class Manager
    {
        public Manager()
        {
            Services = new List<IService>();
            Assembly ServiceAssembly = Assembly.Load(CoreManager.Instance.SettingsInfo.ServicesDLL);
            if (ServiceAssembly != null)
            {
                Type[] Types = ServiceAssembly.GetTypes();
                foreach (Type Type in Types)
                {
                    if (Type.GetInterface("IService", true) != null)
                    {
                        Services.Add((IService)ServiceAssembly.CreateInstance(Type.FullName));
                    }
                }
            }
        }

        public List<IValue> Process(IValue Value)
        {
            List<IValue> Values = new List<IValue>();
            foreach (IService Service in Services)
            {
                IValue OutputValue = Service.Process(Value);
                if (OutputValue != null)
                {
                    Values.Add(OutputValue);
                }
            }
            return Values;
        }

        protected List<IService> Services { get; set; }
    }
}

 

The code above loads the services that it finds in whatever assembly is specified in the settings. You may want to note that you can't really load an assembly based on location. For example you can't have an assembly in directory Services and expect it to find it (unless you set up the app.config or web.config files correctly). It needs to either be in the GAC or the bin for the app (unless, like I said, you set up the app.config to look in a different directory). Past that, it looks for all IService objects which is simply an interface for the services. It then loads each one. The code for the processor manager and session manager look fairly similar. The task manager hasn't been implemented yet though, but will look very similar as well.

If we go back to the original CoreManager class, you'll see that there is one more function: Process. The process function is called every time there is a request. Every time the interface (or input, or whatever) wants to make a request, it calls that function. It in turn gets input from all input sources. Looping through each one, it sends that input to be preprocessed (which is useful if we're dealing with things like images, sound, etc. to get it in the format we need). After that, we send it off to the services. These in turn come back with a list of outputs that we may be interested in. For example if I send in Kung Fu Hustle, one service may give me back a link to play the film, one may give me information on said film, one may give a list of actors, etc. These items are then sent to the processor for post processing (make sure the info is "safe", etc.).  Once that is done, we simply send it off to each output object that wants to be notified. The output object then does what it wants with the information.

That's all there is to it at present. I've also created a single service, processor, and session class so that it runs. Well that and an input object (TextBox) and output object (Label). But at this point the service just acts as an echo, the processor doesn't do anything, and the session class is simply using the web app's built in session. So there isn't much in the way of interesting code to be found there. In the coming weeks I'll build on it though and come up with... something. Anyway, I hope someone out there found this interesting. Oh and before I forget HaterAide, YABOV, and Craig's Utility Library are now using the SVN server on CodePlex. So as I do bug fixes, changes, etc. you can get them a bit faster. Note that I tend to tear things down and rebuild so use it at your own risk. Anyway, take a look, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 12/1/2009 at 11:03 AM
Tags: , , , ,
Categories: C#
Post Information: Permalink | Comments (1) | Post RSSRSS comment feed

Comments

Gut Instinct

Tuesday, January 05, 2010 11:57 AM

trackback

Life Management System Part 3

Life Management System Part 3

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading