I now have the pleasure of introducing to you the apache-24-with-delphi project (https://code.google.com/p/apache-24-with-delphi).
Following a request from a commenter off my previous post, I have posted a solution to problem of how to develop Apache 2.4 modules using Delphi 2010, to a new Google Code Project Subversion repository.
Features include:
The ability to have multiple handlers in one module. Each handler, of course, can have its own separate configuration in the Apache configuration file. You cannot do this with Embarcadero’s solution.
An easy way to define and leverage custom Apache directives. Apache directives are commands and data that are configured in the Apache configuration file.
I have translated the Apache 2.4 headers into Delphi, and created a demo web app in Delphi that works with Apache 2.4.7 – …. well almost. There remains one persistent stubborn bug in the demo. Possibly I have the calling conventions wrong.
Any way, if any Delphi developer is interested in writing for modern Apache servers and would like to collaborate with me, post a comment here, or email me. I need help cracking this bug.
Basically, Apache correctly loads the module, and calls the module’s RegisterHooks subroutine. But shortly after returning from RegisterHooks(), the server crashes.
Update
It’s done. I now have a fully functionally demo web-site, written in Delphi 2010 as an Apache module, that plugs into Apache 2.4.7 . Now, I wonder if Embarcadero would be interested in taking ownership of my solution? ….
From today the Delphi community can leverage the power of the SBD Dependency Injection Framework. Oh happy developer!, you can find the source code at …
The SBD Dependency Injection Framework is … well … a Dependency Injection Framework for Delphi. It consists of two units accompanied by a demo program and fluff. The framework supports all versions of Delphi from 2010 onwards and all platforms and is available for use via the popular aqnd permissive MPL 2.0 license.
Features
For the sake of brevity, I will list only the main features of the framework.
Service oriented
The framework is Service oriented. In this context “Service” means a service accessed via an interface pointer with a defined API. Central to the framework is the Service Provider. The service provider is a service container for it’s clients. The service provider is also a service.
Usage is Attribute oriented
Yes, that’s right – the lazy developer can use attributes to specify automatic injection points. In other Injection Frameworks, the developer would have to write code support constructor injection. In SBD Injection Framework, auto-magical code-less injection of services occurs before the constructor is called, and is driven by the [Injection] attribute.
Example
First let’s start with a couple of service definitions …
type
IBankAccount = interface
['{some guid}']
function Credit( Amount: currency; const Payee: string): boolean;
// Attempt to pay someone (Payee) something (Amount) from my bank account.
// Return True if payment was made.
end;
IProfitAndLossAccount = interface
['{some other guid}']
function DistributeDividend( GrossDividendToPayOut: double): boolean;
// Distribute the dividend to all the share-holders.
end;
Our task is to distribute a company’s profit to it’s shareholders, by implementing an instance of the IProfitAndLossAccount. We will assume that some-one else has already written a suitable IBankAccount service. Here is how we do it ….
type
TProfitAndLossAccount = class( TInterfacedObject, IProfitAndLossAccount)
private
[Injection] FBankAccount: IBankAccount;
function DistributeDividend( GrossDividendToPayOut: double): boolean;
public
[configuration] constructor ServiceModeCreate;
end;
constructor TProfitAndLossAccount.ServiceModeCreate;
begin
end; // Empty constructor!
function TProfitAndLossAccount.DistributeDividend( GrossDividendToPayOut: double): boolean;
begin
// The two shareholders are Jack and Jill
result := FBankAccount.Credit( GrossDividendToPayOut / 2, 'Jack') and
FBankAccount.Credit( GrossDividendToPayOut / 2, 'Jill') and
end;
Notice there is no constructor logic for the dependent service FBankAccount. A suitable service instance is inserted by the framework. If we have a service provider (ServiceProvider: IServiceProvider),
var
PandL: IProfitAndLossAccount;
begin
if ServiceProvider.Gn.Acquire<IProfitAndLossAccount>( PandL) then
PanL.DistributeDividend( 10000.0);
end;
Service implementation discrimination
If we have two different service definitions that just happen to use the same interface pointer type, but serve different purposes (not just different implementations serving the same purpose), the we can discriminate between the two with a “Configuration string”. This is what it looks like …
type
TProfitAndLossAccount = class( TInterfacedObject, IProfitAndLossAccount)
private
[Injection] FBankAccount: IBankAccount;
function DistributeDividend( GrossDividendToPayOut: double): boolean;
public
[configuration('accounting')] constructor ServiceModeCreate;
end;
Now this …
if ServiceProvider.Gn.Acquire<IProfitAndLossAccount>( PandL, 'accounting') then
PanL.DistributeDividend( 10000.0);
will use the above service implementation, but …
if ServiceProvider.Gn.Acquire<IProfitAndLossAccount>( PandL, 'something-else') then
PanL.DistributeDividend( 10000.0);
... will not.
Competing service array versus co-operative service array
You can register an array (“Service file”) of alternate implementations of the one service definition (Interface pointer type, guid + config string). In other frameworks you can only register one implementation per service definition, if you can do multiple, then the service file can only be used competitively (that is to say the client asks for a service instance, and the provider gives one). SBD Dependency Injection framework can offer a file of service implementations either competitively or co-operatively.
Imagine a task of compressing a message. The service definition is “compress this data”. There is lots of ways to compress data. You might have many algorithms at your disposal in the form of registered services. You pick one, acquire an instance from the service provider and solve your problem. That is an example of a competitive service array.
versus
But what about the reverse problem of de-compression, where a standard has not been followed. You need to find the correct compressor to correctly decompress it. As the selection of compressor was not recorded, you really need to get all the decompressor services in stock to examine the compressed data, just to see which one is the one to use. Now you are using an array of service implementations in a co-operative fashion.
Some hard problems can be simplified by leveraging a co-operative array of services. SBD Injection framework, makes acquisition and usage of co-operative services easy and almost code-free. When you acquire co-operative services, instead of one selected service being injected, you get a collection of them. At service registration time, you can define how the collection is made and how it is added to – or just use IInterfaceList.
Documentation
The documentation will be in form of a demo program, some wiki pages of text (like this blog post), and some Help Insight ///<summary> notes. This is a work-in-progress. At the moment, I have done about 30% of the demo.
No singletons
The framework does not define singletons, nor require you to use them. Nice!
But how does it compare to the DI in Delphi-Spring?