Monday, April 4, 2011

Evangelizing XAF,XPO and leading eXpand framework

I am very very happy to announce that I have joined DevExpress as technical evangelist for the Frameworks Team. I believe that it’s not a coincidence that my first name “Apostolos” has a very similar meaning to Evangelist!

I promise to myself and to all of you very exciting times to come  I will do my best to honor this great opportunity and evangelize XAF through out the universe, because its the greatest framework I ever came across.

I am completely overwhelmed and let this movie clip be an expression of my feelings.

My new responsibilities will include posting to XAF and XPO blogs and publish videos for DevExpress TV. I will be than more happy to discuss any problems, questions, and ideas you have and these can easily end up as blog posts or webcasts. I will also be attending lots of meetings around the world so I hope I am able to shake hands with many of you and soon enough.

You can also be sure that I will continue to lead and support eXpand Framework and this blog will remain devoted to it.

I am already in LA to catch up with The Team,and would be absolutely delighted to have a beer or two with anybody who is around. I am can now be reached at apostolis.bekiaris@devexpress.com

And for those of you that wanted to see a picture of the headquarters. here is a nice one

dx-headquarters

 

Happy DXing to all of you!

Subscribe to XAF feed
Subscribe to community feed

DiggIt!

Friday, April 1, 2011

XAF - Quartz JobScheduler module

Update: Explore JobSchedulerTester solution and run the easytests 

In the past few weeks I have been working on creating a XAF wrapper module for Quartz.Net v2 which is is a full-featured, open source job scheduling system that can be used from smallest apps to large scale enterprise systems.
For those who are not familiar with concept of job scheduling, here is some background information. Also, there great tutorial for Quartz, which will give you a good and necessary introduction
Quartz default implementation
Quartz supports several datastores (sqlserver,ce,mysql,imemory etc) that you can utilize by providing an appropriate connection string, same as XPO.
It has a decoupled architecture with just 2 basic entities (JobDetails and Triggers) which are related by Group property. For instance you can create a number of JobDetails, set its Group to “LongRunning”, than create a Trigger with the same Group property. When the trigger is executed, all jobs for that group will run.
There is also a JobDataMap which represents a dictionary that holds serialized values and is used for jobs-triggers communication. You fill it with data when you create a trigger or a job and when they are executed you get that values back for further use.
JobDetails holds a reference of the Type that implements the Quartz.IJob interface where you put the code specific to your job. Quartz instantiates that type using reflection and runs its Execute method using the context parameter that passes all available information (Scheduler instance, JobDataMaps, etc.)
namespace Quartz {
    public interface IJob {
        void Execute(IJobExecutionContext context);
    }
}
That was a description of how Quartz works by default. Now we would want to put a nice-looking and functional UI on top, and we have XAF (+Xpand) to come for the rescue. To provide as much decoupling as possible from the original Quartz implementation I resorted to creating persistent classes with the same set of properties as Quartz ones. I also needed to have a set of controllers to call Quartz API when the Xpand classes are changed. This allows me to be able to design any XAF domain and use the API to interface with Quartz datastore.
Xpand JobScheduler Domain description
First of all we have the same basic entities XpandJobDetail, XpandJobTrigger. A JobSchedulerGroup was introduced to achieve the default quartz relationship as shown below:
image
Additionally a many to many relationship between XpandJobDetail and XpandJobTrigger has been added allowing you to associate triggers, and jobs (even if they not belong to any group).
image
A new type of trigger the JobListenerTrigger was introduced in order to be able to trigger a job after an event of another job was executed
image
Now our XpandJobDetail stores a reference to the Quartz.IJob interface using the Persistent XpandJob object (the same way Quarz does). However, one would have to decorate this class with JobDetailDataMapType or JobDataMapType attribute in order to tell XAF which XpandJobDataMap to associate with the XpandJobDetail or XpandJob And, as you already guessed, JobDataMap, that is dictionary instance for Quartz, is populated from XAF persistent classes.
Bellow you see the sample ThresholdCalculationJob provided by Xpand.ExpressApp.JobScheduler.Jobs assembly:
[System.ComponentModel.DisplayName("ThresholdJob")]
[JobDetailDataMapType(typeof(ThresholdJobDetailDataMap))]
public class ThresholdCalculationJob : IJob {
    public const string ThresholdCalcCount = "ThresholdCalcCount";
    readonly ILog log = LogManager.GetLogger(typeof(ThresholdCalculationJob));
    public void Execute(IJobExecutionContext context) {
        log.Info("EXECUTING:ThresholdCalculationJob");
        var application = ((IXpandScheduler)context.Scheduler).Application;
        var objectSpaceProvider = application.ObjectSpaceProvider;
        var jobDataMap = context.JobDetail.JobDataMap;
        var typeInfo = objectSpaceProvider.TypesInfo.FindTypeInfo((Type)jobDataMap.Get<ThresholdJobDetailDataMap>(map => map.DataType));
       object count;
       using (var unitOfWork = new UnitOfWork(((ObjectSpaceProvider)objectSpaceProvider).WorkingDataLayer)) {
            count = unitOfWork.GetCount(typeInfo.Type, CriteriaOperator.Parse(jobDataMap.GetString<ThresholdJobDetailDataMap>(map => map.Criteria)));
       }
       jobDataMap.Put<ThresholdJobDetailDataMap>(ThresholdCalcCount, count);
    }
}
Viola! We get a XafApplication instance and off we go using our usual XAF routines!
Apart from the XafApplication instance, the above code has some other interesting details, e.g.
var typeInfo = objectSpaceProvider.TypesInfo.FindTypeInfo((Type)jobDataMap.Get<ThresholdJobDetailDataMap>(map => map.DataType));
Here we are requesting the DataType property value from ThresholdJobDetailDataMap object (didn’t I already tell you that our XpandJobDetails have JobDataMaps are simply XAF persistent objects?).
The server
Xpand provides a very easy way to configure Xpand.Quartz.Server assembly. Server is built with the TopShelf framework, that means you can either run it as a console app or as a windows service (using –install as parameter) . Server is responsible of executig all jobs (classes that implement that Quartz.IJob interface).
One thing you have to remember is that, since Server instantiates XafApplication, the configuration file on the server has to be synchronized with the one on the client.
In order for the server to know which XafAppliation to create the following change is needed:image
The Demo
Xpand FeatureCenter has a special assembly (Xpand.ExpressApp.JobScheduler.Jobs) that provides 2 sample job, the ThresholdCalculationJob that you saw already and SendThresholdCalculationEmailJob. Also there is a new EmailTemplateEngine that has been build in order to support the SendThresholdCalculationEmailJob which is naturally based on persistent objects and that can be configured runtime.
The scripts that create a Quartz database can be found in eXpand sources under Resource/Quartz folder. Quartz database has to be created in order to run the demo from FeatureCenter.
To give you a better idea about above mentioned functionality and to show what the sample application (Feature Center in this case) that uses JobScheduler module may look like, here is a short screen cast:

You can d/l eXpand Framework latest version from http://expandframework.com/downloads and sent use your feed back at our forums

Subscribe to XAF feed
Subscribe to community feed

DiggIt!