Página principal
Artículos y trucos
Catálogo de productos
Ejemplos y descargas
Mis libros
Cursos de formación
Investigación y desarrollo
Libros recomendados
Mis páginas favoritas
Acerca del autor
 
En colaboración con Amazon
 
Intuitive Sight

Cadenas de construcción en COM+

Aprovechando un poco de tiempo libre que milagrosamente ha aparecido, me he dedicado a preparar la segunda versión de Classique, el sistema de comercio electrónico de IntSight. Como todavía hay fallos importantes en el controlador de DB Express para SQL Server, esta vez he vuelto a utilizar ADO Express para el acceso a datos, y para no aburrirme demasiado, he hecho un par de experimentos con módulos transaccionales: módulos de datos remotos de DataSnap que se registran como clases COM+ dentro del Catálogo de COM+. En algún momento tendré que escribir un artículo para explicar las ventajas de utilizar este tipo de módulos... y los peligros que hay que evitar, por supuesto. Pero ahora quiero explicar una técnica muy útil para personalizar las instalaciones de clases COM+ sin necesidad de tocar una línea del código fuente.

CONFIGURANDO UNA CADENA DE CONSTRUCCION

La siguiente imagen corresponde al cuadro de diálogo de propiedades de una clase COM+, una vez registrada en el Catálogo:

Cadenas de construcción

La opción que quiero explicar es la que aparece en el segundo grupo: Habilitar construcción de objetos. Inicialmente, esta opción se encuentra inactiva para una clase recién instalada. Pero, como en nuestro ejemplo, podemos activarla, y teclear una cadena arbitraria en el cuadro de edición Cadena del constructor.

¿Qué sucede cuando hacemos tal cosa? Pues que cada vez que COM+ crea un objeto perteneciente a dicha clase, le pasa (ahora explicaré cómo) la cadena que hemos introducido en el Catálogo. ¿El objetivo? Simplemente permitir al administrador del sistema personalizar los objetos de dicha clase, en formas previstas, claro está, por el desarrollador de la misma. Piense, por ejemplo, en un módulo de datos transaccional que use ADO, como éste de Classique: el módulo debe contener un TADOConnection al que se deben conectar todas las consultas y procedimientos almacenados. ¿A qué servidor debe conectarse el componente? ¿Qué opciones debe activar la conexión? A priori, es imposible que el desarrollador pueda saberlo, porque por lo general el nombre del servidor SQL será diferente en cada instalación. Por este motivo, podemos hacer que la cadena de conexión que debe asignarse en la propiedad ConnectionString del TADOConnection se pueda configurar en el Catálogo COM+.


Por supuesto, existen mil y una formas alternativas de pasar la cadena de conexión: el registro, un fichero UDL, ficheros INI... No obstante, tenga en cuenta que usar el Catálogo COM+ es mucho más "limpio". Y que, de todos modos, siempre es bueno tener algún truco de este tipo bajo la manga.

RECIBIENDO UNA CADENA DE CONSTRUCCION

Ahora bien, ¿cómo puede el componente recibir la cadena configurada? Cuando activamos la opción mencionada, COM+ espera que la clase correspondiente haya implementado la interfaz IObjectConstruction, que Delphi define dentro de la unidad ComSvcs:

type
   IObjectConstruct = interface(IUnknown)
      ['{41C4F8B3-7439-11D2-98CB-00C04F8EE1C4}']
      function Construct(const pCtorObj: IDispatch): HResult; stdcall;
   end;

Si no se cumple dicho requisito, COM+ produce una excepción y no se lleva a cabo la construcción del objeto. Pero si todo va bien, COM+ pide al objeto el puntero a la interfaz en cuestión, y ejecuta su método Construct. Puede parecer extraño que el parámetro de Construct sea otro objeto, en vez de pasar directamente la cadena almacenada en el Catálogo. Pero está claro que se trata de una previsión de COM+ para que, en hipotéticas versiones futuras, se puedan establecer opciones de construcción más sofisticadas. Lo que sí es una chapuza es que el parámetro pasado sea del tipo de interfaz IDispatch. Esto es culpa, como muchas otras chapuzas de Windows, del maldito Visual Basic, que solamente se siente cómodo con IDispatch, para realizar llamadas mediante Automatización OLE. No obstante, COM+ nos garantiza que el objeto al que pertenece la interfaz también implementa esta otra, también declarada en ComSvcs:

type
   IObjectConstructString = interface(IDispatch)
      ['{41C4F8B2-7439-11D2-98CB-00C04F8EE1C4}']
      function get_ConstructString: WideString; safecall;
   end;

Y lo que sí es una chapuza de Delphi es que la primera de estas interfaces se declare directamente con el modelo de llamadas stdcall, mientras que sólo la segunda utiliza safecall, que simplifica mucho la ejecución desde Delphi.

Con esta información en la mano, es fácil deducir qué tenemos que hacer con nuestro módulo remoto transaccional para que pueda recibir una cadena de construcción, en el caso de que el administrador del sistema haya configurado una. Para empezar, tenemos que añadir el tipo de interfaz IObjectConstruct a la lista de interfaces implementadas por el módulo, y crear un método Construct dentro de nuestra clase:

type
   TDataServer = class(TMtsDataModule, IDataServer, IObjectConstruct)
      ADOConn: TADOConnection;
      // ...
   protected
      function Construct(const pCtorObj: IDispatch): HResult; stdcall;
      // ...
   end;

La implementación de Construct puede ser tan sencilla como la que muestro a continuación:

function TDataServer.Construct(const pCtorObj: IDispatch): HResult;
var
   OCS: IObjectConstructString;
   CS: WideString;
begin
   if pCtorObj.QueryInterface(IObjectConstructString, OCS) = 0 then
      CS := OCS.get_ConstructString;
   if CS <> '' then
      ADOConn.ConnectionString := CS;
   Result := S_OK;
end;

Por supuesto, es muy recomendable que el componente de conexión haya previsto una cadena de conexión por omisión suficientemente razonable, o algún mecanismo alternativo de configuración, para el caso en que el administrador no suministre una cadena de construcción personalizada para la clase.