TFactory (seconda parte)

  • uncategorized
  • 518 words

Come avevo anticipato (o no?) ecco il codice della Factory che carica Classi a Run-Time (tipo Plug-In) in C++.
E’ anche (indecentemente) commentata, quindi: divertitevi…

#ifndef TFACTORY_H
#define TFACTORY_H
#include “TFactoryException.h”
#include // Libreria "Dynamic Lynking Loader"

/**
* @class TFactory TFactory.h
* Questa Classe Template ha il compito di @b Istanziare @b a @b Run-Time Classi
* la cui Dichiarazione e Definizione non e’ avvenuta a @b Compile-Time.
* In sostanza, si parla di realizzare un sistema per la gestione
* di quelli che, in gergo, si chiamano @b Plug-In: mini-programmi che
* si aggiungono ad altri piu’ grandi per aumentarne le funzionalita’.
*
* E’ una “Factory” di Classi @a Plug-In.

* Carica da libreria SO la definizione di una Classe che ha come
* Classe di Base il Parametro passato alla Factory: in questo modo e’
* sufficiente, per realizzare classi Plug-In, che le Classi da Istanziare
* a Run-Time implementino un’interfaccia comune.
*
* Per la precisione, e’ anche necessario che nella libreria SO che
* contiene la classe sia presente una funzione cosÏ definita:


*
*
* extern “C”

* *buildObject(void) { return new ; }

*

*
* @c buildObject(void) crea effettivamente una istanza della Classe Plug-In.
*
* Questa soluzione permette quindi di caricare nuove Classi senza
* bisogno ne di ricompilare, ne di modificare il codice. */
template
class TFactory {
public:
TFactory(const string &);
~TFactory();
T build () ;
void closeSo();

private:
/* Handler della SO caricata */
void *handler;
/* Puntatore alla funzione (o, meglio, al “simbolo”)
* ritornato da “dlsym” */
T (*builder)(void);
void openSo(const string &);
};

/**
* Costruttore TFactory.
* Si occupa anche di recuperare i Simboli (@c “buildObject” )
* necessari all’istanziazione di una nuova T Class.
*
* @param soLibPath Path alla Libreria SO da dove caricare la definizione
* della Classe */
template
TFactory::TFactory(const string &soLibPath) {
try {
/* Caricamento della SO */
openSo(soLibPath);
/* Casting necessario per una corretta assegnazione
* della funzione al relativo puntatore */
*(void **) (&builder) = dlsym(handler, “buildObject”);
/* Controlla che il Simbolo Cercato (“buildObject”) sia
* stato trovato… */
if ( builder == NULL ) { // Errore nel caricamento della funzione
/* …in caso negativo, lancia un TFactoryException */
string exceptionMessage(“ ERROR: ");
exceptionMessage += dlerror();
throw TFactoryException(exceptionMessage);
}
}
catch ( TFactoryException &e ) {
throw e;
}
cout « “ Plug-In Loaded. Library-Path: "<<>
}

/** Distruttore TFactory */
template
TFactory::~TFactory() {}

/**
* Restituisce una istanza della Classe contenuta nella SO.
* L'oggetto restituito e' UP-Castato alla Classe Base "T"
* (parametro del Template)
* @return Una nuova istanza di T (T = Parametro di TFactory) */
template
T TFactory::build() {
return ( (*builder)() ); // Ritorna la nuova istanza di T
}

/**
* Carica la libreria SO.
*
* @param soLibPath Libreria SO da caricare */
template
void TFactory::openSo(const string &soLibPath) {
/* Apertura della Libreria SO */
handler = dlopen( soLibPath.data(), RTLD_NOW);

if (!handler) {
string exceptionMessage(" ERROR: ");
exceptionMessage += dlerror();
throw TFactoryException(exceptionMessage);
}
}

/** Chiude la libreria SO */
template
void TFactory::closeSo() {
if (handler) {
dlclose(handler);
handler = NULL;
}
}

#endif</span></span>

Per una migliore lettura, consiglio un bel Cut&Paste, magari in qualche Beautifier...<div style="clear:both; padding-bottom: 0.25em;"></div>