User Tools

Site Tools


legacy:manuals:es:develop:the_greenstone_runtime_system

EL SISTEMA DE EJECUCIÓN DE GREENSTONE

En este capítulo se explica el sistema de ejecución de Greenstone a fin de que usted pueda comprender, aumentar y ampliar sus posibilidades. El programa está escrito en C++ y hace un uso importante de la “herencia virtual”. Si no conoce bien este lenguaje, es preferible que lo aprenda antes de seguir adelante. Deitel y Deitel (1994) propone un manual de introducción general, pero Stroustroup (1997) es la referencia de mayor autoridad.

Empezaremos explicando la filosofía conceptual que sustenta el sistema de ejecución, ya que influye considerablemente en su implementación. Luego pasaremos a examinar  detalladamente la implementación, que constituye la parte principal de este capítulo. La versión de Greenstone que se expone aquí es la versión CGI (Biblioteca Web para los usuarios de Windows). La versión Biblioteca Local de Windows utiliza el mismo código fuente pero tiene un servidor Web incorporado como interfaz de usuario. Además, la Biblioteca Local es un proceso de tipo persistente.

Estructura de los procesos

<imgcaption figure_overview_of_a_general_greenstone_system|%!– id:760 –%Resumen gráfico de un sistema Greenstone general ></imgcaption>

En la Figura <imgref figure_overview_of_a_general_greenstone_system> aparecen varios usuarios, representados por computadoras en la parte superior del diagrama, que acceden a tres colecciones de Greenstone. Antes de ser puestas en línea, estas colecciones pasan por los procesos de importación y creación expuestos en los capítulos anteriores. En primer lugar, los documentos, que aparecen en la parte inferior de la figura, se importan en el Formato de Archivo  Greenstone, que es un formato XML. A continuación, los archivos en el Formato de Archivo Greenstone se incorporan a varios índices de búsqueda y a una base de datos de informaciones de la colección que incluye las estructuras jerárquicas necesarias para las operaciones de consulta. Una vez hecho esto, la colección está lista para ser puesta en línea y responder a las solicitudes de información.

Los dos componentes fundamentales en la concepción del sistema de ejecución son los “recepcionistas” y los “servidores de colección”. Desde el punto de vista del usuario, un recepcionista es el punto de contacto con la biblioteca digital. Recibe los datos proporcionados por los usuarios mediante el teclado y los clics del ratón, los analiza y luego transmite una solicitud al correspondiente servidor (o servidores) de la colección. Este último localiza la información solicitada y la envía al recepcionista para que la presente al usuario. Los servidores de colección actúan como un mecanismo abstracto que administra el contenido de la colección, mientras que los recepcionistas se encargan de la interfaz de usuario.

<imgcaption figure_greenstone_system_using_the_null_protocol|%!– id:763 –%Resumen gráfico de un sistema Greenstone general ></imgcaption>

Como se muestra en la Figura <imgref figure_overview_of_a_general_greenstone_system>, los recepcionistas se comunican con los servidores de colección mediante un protocolo definido. La implementación de este protocolo depende de la configuración de la computadora en la que se ejecuta el sistema de biblioteca digital. El caso más común, y el más sencillo, es cuando hay un recepcionista y un servidor de colección y ambos operan en la misma computadora. Eso es lo que se obtiene con la instalación por defecto de Greenstone. En este caso, los dos procesos se combinan para formar un solo ejecutable (denominado library) y, por consiguiente, la utilización del protocolo se reduce a llamadas de función. A esto lo llamamos null protocol (protocolo nulo) y es la base del sistema estándar de biblioteca digital Greenstone en su estado original. Esta configuración simplificada aparece en la Figura <imgref figure_greenstone_system_using_the_null_protocol>, en la que el recepcionista, el protocolo y el servidor de colección están unidos en una sola entidad, el programa library (biblioteca). La finalidad de este capítulo es explicar cómo funciona.

Normalmente, un “servidor” es un proceso persistente que, una vez iniciado, funciona indefinidamente y responde a cualquier solicitud que le llegue. No obstante, a pesar de su nombre, el servidor de colección en la configuración de protocolo nulo no es un servidor en el sentido estricto. De hecho, cada vez que se solicita una página Web de Greenstone, se arranca el programa library (mediante el mecanismo CGI), éste responde a la solicitud y luego se cierra. Lo llamamos “servidor” porque también está diseñado para funcionar con una configuración más general como la de la Figura <imgref figure_overview_of_a_general_greenstone_system>.

Por más sorprendente que parezca, este ciclo de arranque, tratamiento y cierre no es tan lento como se podría imaginar y el resultado es un servicio perfectamente utilizable. Sin embargo, el sistema es poco eficiente. Existe un mecanismo llamado Fast-CGI ( www.fastcgi.com ) que ofrece una buena solución de compromiso. Gracias a su utilización, el programa library puede permanecer en memoria después de la primera ejecución y recibir las subsiguientes series de argumentos CGI, con lo que se evita repetir la inicialización y su función se asemeja más a la de un servidor convencional. La utilización de Fast-CGI es una opción de Greenstone y se activa volviendo a compilar el código fuente con las bibliotecas adecuadas.

Como alternativa al protocolo nulo, hemos elaborado también el protocolo Greenstone utilizando el famoso sistema CORBA (Slama et al., 1999), que utiliza un paradigma unificado orientado a objetos, para permitir a distintos procesos ejecutándose en distintas plataformas informáticas e implementados en diferentes lenguajes de programación, acceder a la misma serie de objetos distribuidos por Internet (o cualquier otra red). Así pues, una situación como la de la Figura <imgref figure_overview_of_a_general_greenstone_system>, en la que todos los recepcionistas y los servidores de colección operan en diferentes computadoras, es perfectamente viable.

<imgcaption figure_graphical_query_interface_to_greenstone|%!– id:768 –%Interfaz gráfica de consultas de Greenstone ></imgcaption>

Ello permite la instalación de interfaces mucho más complejas para distribuir exactamente las mismas colecciones de biblioteca digital. A modo de ejemplo, en la Figura <imgref figure_graphical_query_interface_to_greenstone> se muestra una interfaz gráfica de consultas, basada en los diagramas de Venn, que permite a los usuarios manipular directamente las consultas booleanas. Escrita en Java, la interfaz funciona localmente en la computadora del usuario. Con el sistema CORBA, se puede acceder a un servidor remoto de colección de Greenstone, escrito en C++.

No nos extenderemos más sobre este tema en el presente manual, ya que el protocolo distribuido sigue siendo objeto de perfeccionamiento y mejoras para su utilización (para obtener más información, véase Bainbridge et al., 2001).

Marco conceptual

<imgcaption figure_generating_the_about_this_collection_page|%!– id:772 –%Generación de la página “Acerca de esta colección” ></imgcaption>

En la Figura <imgref figure_generating_the_about_this_collection_page> se muestra la página “Acerca de esta colección” de una colección Greenstone particular (la colección del Proyecto Gutenberg). Fíjese en la dirección URL que aparece en la parte superior: esta página se obtiene activando el programa CGI library, que es el ejecutable anteriormente mencionado en que el recepcionista y el servidor de colección están conectados mediante el protocolo nulo. Los argumentos del programa library son c=gberga=pp=about y l=es. Pueden interpretarse del modo siguiente:

Para acceder a la colección del Proyecto Gutenberg (c=gberg), la acción consiste en crear una página (a=p) y la página que hay que generar se llama “about” (p=about), en español (l=es).

<imgcaption figure_greenstone_runtime_system|%!– id:775 –%Sistema de ejecución de Greenstone ></imgcaption>

La Figura <imgref figure_greenstone_runtime_system> ilustra las principales partes del sistema de ejecución de Greenstone. En la parte superior, el recepcionista inicializa primero sus componentes, luego analiza los argumentos CGI para decidir qué acción activar. Al ejecutar la acción (que incluye nuevos tratamientos de los argumentos CGI), el programa utiliza el protocolo para acceder al contenido de la colección. Se utiliza la respuesta para generar una página Web, con la asistencia del componente de formato y del lenguaje de macros.

El lenguaje de macros, que ya examinamos en la Sección controlling_the_greenstone_user_interface, se utiliza para conferir al sistema de Biblioteca Digital Greenstone un estilo coherente y crear interfaces en diferentes lenguas. La interacción con la biblioteca genera la estructura básica de las páginas Web y las macros del directorio GSDLHOME/macros aportan el contenido.

El objeto Lenguaje de macros representado en la Figura <imgref figure_greenstone_runtime_system> se encarga de leer estos archivos y de memorizar el resultado del análisis. Cualquier acción puede utilizar este objeto para ampliar una macro. Puede incluso crear nuevas definiciones de macro e invalidar las anteriores, aportando así una dimensión dinámica al uso de las macros.

La representación de la página “Acerca de esta colección” (Figura <imgref figure_generating_the_about_this_collection_page>) se conoce antes de la ejecución y está codificada en el archivo de macros about.dm. Los encabezados, los pies de página y la imagen de fondo ni siquiera se mencionan porque se encuentran en el paquete de macros Global. Sin embargo, el texto específico de “acerca de” correspondiente a una colección particular no se conoce de antemano, sino que se guarda en la base de datos de informaciones de la colección durante el proceso de creación. Esta información se recupera mediante el protocolo y se guarda como macro _ collectionextra_ en el paquete de macros Global. Obsérvese que este nombre de macro es prácticamente el mismo que se empleó para expresar esta información en el archivo de configuración de colección mencionado en la Sección import_and_build_processes. Para generar el contenido de la página, se amplía la macro _ content _ en el paquete about (que se muestra en la Figura <imgref figure_part_of_the_aboutdm_macro_file>). Esta operación amplía a su vez _ textabout _, que accede a la macro _ collectionextra _ que acababa de colocarse allí de manera dinámica.

Otro componente importante es el objeto Formato. Las instrucciones de formato en el archivo de configuración de colección inciden en la presentación de determinados elementos de información, como se explica en la Sección formatting_greenstone_output. Su gestión corre a cargo del objeto Formato representado en la Figura <imgref figure_greenstone_runtime_system>. La principal tarea de este objeto es analizar y evaluar instrucciones como las cadenas de formato de la Figura <imgref figure_excerpt_from_the_demo_collection_collect>. Tal como vimos en la Sección formatting_greenstone_output, éstas pueden comprender referencias a metadatos entre corchetes (por ejemplo, [Title]), que han de recuperarse del servidor de colección. Se producen interacciones entre el objeto Formato y el objeto Lenguaje de macros, ya que las instrucciones de formato pueden incluir macros, que cuando se amplían incluyen metadatos, y cuando éstos se amplían a su vez incluyen macros, y así sucesivamente.

El servidor de colección, visible en la parte inferior de la Figura <imgref figure_greenstone_runtime_system>, experimenta también un proceso de inicialización, en el que establece objetos Filtro y de fuente para responder a las solicitudes que recibe del protocolo, y un objeto Búsqueda para prestar asistencia en esta tarea. En última instancia, los objetos acceden a los índices y las bases de datos de informaciones de colección, ambos elaborados durante la creación de la colección.

Sin contar las líneas en blanco, el recepcionista contiene 15.000 líneas de código. El servidor de colección sólo contiene 5.000 líneas, el 75% de las cuales están ocupadas por archivos de encabezado. El servidor de colección es más compacto porque la recuperación de los datos se lleva a cabo mediante dos programas precompilados. Se utiliza MG, un sistema de recuperación de texto completo, para las búsquedas y GDBM, un sistema de gestión de bases de datos, para la gestión de la base de datos de informaciones de colección.

Para facilitar la extensibilidad y la flexibilidad, Greenstone utiliza considerablemente el método de herencia, en particular, en los objetos Acción, Filtro, Fuente y Búsqueda. Esto significa que, para manejar una simple biblioteca digital que sólo contenga colecciones de textos, usted tiene que aprender un poco más para programar el sistema. No obstante, esto también significa que MG y GDBM podrían sustituirse fácilmente si ello fuera necesario. Además, la arquitectura del programa es lo suficientemente rica para admitir todas las posibilidades multimedia, como el control de la interfaz por medio de sistemas de reconocimiento de voz o  consultas en forma de gráfica.

Ajuste del marco conceptual

En las Secciones collection_server y receptionist se explica más detalladamente el funcionamiento del servidor de colección y del recepcionista, se amplía la información sobre los módulos de la Figura <imgref figure_greenstone_runtime_system> y se explica su implementación. Es conveniente, en primer lugar, ilustrar con ejemplos la interacción de un usuario con el programa Greenstone y luego explicar lo que sucede “entre bastidores”. De momento, supondremos que todos los objetos están inicializados correctamente. La inicialización es un procedimiento bastante complejo que reexaminaremos en la Sección initialisation.

Efectuar una búsqueda

<imgcaption figure_searching_gutenberg_for_darcy|%!– id:787 –%Búsqueda de Darcy en el Proyecto Gutenberg ></imgcaption>

Cuando un usuario introduce una consulta y pulsa Iniciar la búsqueda en la página de búsqueda, se activa una acción Greenstone que culmina generando una nueva página HTML mediante el lenguaje de macros. En la Figura <imgref figure_searching_gutenberg_for_darcy> se muestra el resultado de la búsqueda del nombre Darcy en la colección del Proyecto Gutenberg. La instrucción a=q se encuentra oculta en el HTML de la página original de búsqueda. Cuando se pulsa el botón de búsqueda se activa esta instrucción y se ejecuta la nueva acción queryaction. La ejecución de queryaction consiste en una llamada al objeto Filtro de la colección designada ( c=gberg) a través del protocolo.

Los filtros desempeñan una función básica importante en los servidores de colección. Adaptados a las actividades de búsqueda y consulta, los filtros permiten seleccionar un subconjunto de información en una colección. En este caso, queryaction inicia una solicitud de filtro:

  • estableciendo que el tipo de solicitud de filtro es QueryFilter (los distintos tipos de filtro se explican en la Sección collection_server);
  • memorizando las preferencias de búsqueda del usuario – reconocimiento de mayúsculas y minúsculas, truncamiento, etc.– en la solicitud de filtro;
  • activando la función filter() mediante el protocolo nulo.

Las llamadas al protocolo son síncronicas. El recepcionista queda efectivamente bloqueado hasta que el servidor de colección trata la solicitud de filtro y se envían los datos generados.

Cuando se hace una llamada de protocolo de tipo QueryFilter, el objeto de filtro (véase la Figura <imgref figure_greenstone_runtime_system>) descodifica las opciones y llama al objeto Búsqueda, que utiliza MG para efectuar la búsqueda propiamente dicha. La función del objeto Búsqueda es proporcionar una interfaz abstracta de programa que permita la búsqueda, independientemente de la herramienta de búsqueda subyacente que se utilice. El formato utilizado para enviar los resultados recurre también a la abstracción, lo cual obliga el objeto Búsqueda a traducir los datos generados por la herramienta de búsqueda a una forma normalizada.

Una vez enviados los resultados de búsqueda al recepcionista, se procede a formatearlos para su presentación utilizando los objetos Formato y Lenguaje de macros. Como se muestra en la Figura <imgref figure_searching_gutenberg_for_darcy>, esta operación supone: la creación del encabezado, el pie de página, la barra de desplazamiento y la imagen de fondo normalizados de Greenstone; la repetición de la parte principal de la página de consulta justo debajo de la barra de desplazamiento; y la presentación de un icono de libro, así como el título y el autor para cada uno de los resultados de la búsqueda. El formato de esta última parte depende de la instrucción format SearchVList que se encuentra en el archivo de configuración de la colección. Para poder mostrar los metadatos de título y autor, éstos han de recuperarse antes del servidor de colección, lo que requiere nuevas llamadas al protocolo, pero esta vez utilizando BrowseFilter (filtro de consulta).

Recuperación de un documento

Siguiendo con la búsqueda anterior de Darcy, obsérvese lo que sucede cuando visualiza un documento. En la Figura <imgref figure_the_golf_course_mystery> se muestra el resultado de pulsar el icono que se encuentra junto a The Golf Course Mystery en la Figura <imgref figure_searching_gutenberg_for_darcy>.

<imgcaption figure_the_golf_course_mystery|%!– id:798 –%The Golf Course Mystery ></imgcaption>

El texto de origen de la colección Gutenberg consiste en un extenso archivo por cada libro. Durante la creación de la colección, dichos archivos se dividen en páginas separadas cada 200 líneas aproximadamente, y las informaciones importantes de cada página se guardan en los índices y en la base de datos de informaciones de la colección. En la parte superior de la Figura <imgref figure_the_golf_course_mystery> se indica que este libro tiene 104 páginas electrónicas, y justo debajo aparece el principio de la primera página: el nombre de la persona que introdujo el texto, el título, el autor y el principio de un índice (dicho índice forma parte del texto de origen del Proyecto Gutenberg y no ha sido generado por Greenstone). En la parte superior izquierda se ven los botones que controlan la presentación del documento: una sola página o la totalidad del documento, si se resalta o no el término de la consulta, y si se muestra o no el libro en su propia ventana, separado de la actividad principal de búsqueda y consulta. En la parte superior derecha hay un asistente de consulta que proporciona acceso directo a cualquier página del libro: basta con escribir el número de la página y pulsar el botón “ir a la página”. Asimismo, se pueden consultar las páginas anteriores y posteriores haciendo clic en los iconos de flecha situados de cada lado del dispositivo de selección de página.

La operación de recuperación de documentos, documentaction, se especifica mediante la configuración a=d y requiere varios argumentos suplementarios. Lo más importante es el documento por recuperar: éste se define mediante la variable d. En la Figura <imgref figure_the_golf_course_mystery> su valor es d=HASH51e598821ed6cbbdf0942b.1 para recuperar la primera página del documento cuyo identificador es HASH51e598821ed6cbbdf0942b, y que en términos más convencionales se conoce como The Golf Course Mystery. Hay otras variables mediante las cuales se determina si el término de búsqueda ha de resaltarse o no ( hl) y qué página del libro se debe mostrar ( gt). Estas variables complementan las opciones propuestas por los botones de la página Web representados en la Figura <imgref figure_the_golf_course_mystery> y antes mencionados. Se utilizan los valores por defecto cuando se omite cualquiera de estas variables.

Esta acción sigue un procedimiento similar a queryaction : examen de los argumentos CGI, acceso al servidor de colección mediante el protocolo y utilización del resultado para generar una página Web. Las opciones relativas al documento se descodifican a partir de los argumentos CGI y se guardan en el objeto para operaciones ulteriores. Para recuperar el documento desde el servidor de colección, sólo se necesita el identificador de documento para efectuar la llamada de protocolo get_document(). Una vez enviado el documento, queda por hacer un trabajo considerable de formateo. Para ello, el código de documentaction accede a los argumentos almacenados y utiliza los objetos Formato y Lenguaje de macros.

Consulta de un clasificador jerárquico

En la Figura <imgref figure_browsing_titles_in_the_gutenberg_collection> se muestra un ejemplo de consulta, en que el usuario ha elegido títulos a-z y ha accedido al hipervínculo de la letra K. Esta operación se basa también en documentaction, función proporcionada por la especificación del argumento CGI a=d, como en el caso anterior. Sin embargo, la diferencia es que antes se incluyó la variable d y esta vez no. En su lugar, el nodo de la jerarquía de clasificación por visualizar se especifica con la variable cl, que en este caso representa los títulos agrupados bajo la letra K. Esta lista se constituyó durante el proceso de creación y está guardada en la base de datos de informaciones de la colección.

<imgcaption figure_browsing_titles_in_the_gutenberg_collection|%!– id:804 –%Consulta de los títulos de la colección Gutenberg ></imgcaption>

Los registros que representan nodos de clasificador en la base de datos utilizan el prefijo CL, seguido de números separados por puntos (.) para indicar dónde se encuentran dentro de la estructura de subdivisiones. Si se ignora el botón de búsqueda (visible en el extremo izquierdo de la barra de desplazamiento), los clasificadores se numeran secuencialmente por orden ascendente, de izquierda a derecha, empezando por 1. Así pues, el nodo de clasificador de primer nivel para los títulos en nuestro ejemplo es CL1, y la página buscada se obtiene indicando cl=CL1.11, como puede verse en la dirección URL que aparece en la parte superior de la Figura <imgref figure_browsing_titles_in_the_gutenberg_collection>.

Para tratar una solicitud de documento de tipo cl, se utiliza el objeto Filtro para recuperar el nodo a través del protocolo. Según los datos enviados, se efectúan ulteriores llamadas de protocolo para recuperar los metadatos de los documentos. En este caso, se obtienen los títulos de los libros. Sin embargo, si se tratara de un nodo interno cuyos elementos secundarios fueran a su vez nodos, se recuperarían también los títulos de los nodos secundarios. Desde el punto de vista de la codificación es lo mismo y de ello se encarga el mismo mecanismo.

Por último, toda la información recuperada se interconecta mediante el lenguaje de macros a fin de crear la página Web que se muestra en la Figura <imgref figure_browsing_titles_in_the_gutenberg_collection>.

Generación de la página principal

<imgcaption figure_greenstone_home_page|%!– id:809 –%Página principal de Greenstone ></imgcaption>

Como último ejemplo, examinaremos el caso de la generación de la página principal de Greenstone. En la Figura <imgref figure_greenstone_home_page> se muestra –en el caso de la instalación por defecto de Greenstone– su página principal tras la instalación de algunas colecciones de prueba. La dirección URL, que puede verse en la parte superior de la pantalla, incluye los argumentos a=p y p=home. Así pues, al igual que en el caso de la página “Acerca de esta colección”, ésta se genera mediante una pageaction (a=p), pero esta vez la página creada es home ( p=home). Por consiguiente, el lenguaje de macros accede al contenido del archivo home.dm. En este caso no es necesario especificar una colección (mediante la variable c).

La finalidad de la página principal es mostrar las colecciones disponibles. Cuando el usuario hace clic en un icono, aparece la página “Acerca de esta colección” de la colección correspondiente. Cada vez que se carga la página, se genera dinámicamente el menú de las colecciones basándose en las colecciones que se encuentran en el sistema de archivos en ese momento. Cuando una nueva colección se pone en línea, aparece automáticamente en la página principal cuando ésta se vuelve a cargar, siempre que se haya especificado que la colección es “pública”.

Para ello, el recepcionista utiliza, desde luego, el protocolo. Como parte de su función de evaluación de los argumentos CGI, la acción pageaction está programada para detectar el caso particular p=home. A continuación, la acción utiliza la llamada de protocolo get_collection_list() para establecer el conjunto de colecciones que se encuentran en línea y activa get_collectinfo() a fin de obtener información sobre cada una de ellas. Dicha información indica si la colección puede consultarse públicamente, cuál es la dirección URL del icono de la colección (si es que existe) y el nombre completo de la colección. Estos datos se utilizan para generar una entrada apropiada de la colección en la página principal.

El código fuente

<tblcaption table_standalone_programs_included_in_greenstone|Programas autónomos incluidos en Greenstone></tblcaption>

< - 132 397 >
setpasswd/ Ayuda para las contraseñas bajo Windows.
getpw/ Ayuda para las contraseñas bajo Unix.
txt2db/ Convierte un formato de texto ASCII de tipo XML en formato de base de datos de GNU.
db2txt/ Convierte el formato de base de datos de GNU en formato de texto ASCII de tipo XML.
phind/ Herramienta de consulta jerárquica en los grupos de palabras.
hashfile/ Calcula un identificador de documento único, basándose en el contenido del archivo.
mgpp/ Versión reescrita y actualizada del paquete Managing Gigabytes en C++
w32server/ Servidor de Biblioteca Local para Windows.
checkis/ Ayuda específica para la instalación de Greenstone bajo Windows.

El código fuente del sistema de ejecución se encuentra en GSDLHOME/src. Ocupa dos subdirectorios, recpt para el código del recepcionista y colservr para el del servidor de colección. Greenstone funciona bajo Windows a partir de la versión Windows 3.1, lo cual impone desafortunadamente un máximo de ocho caracteres en los nombres de archivos y directorios. Esto explica la utilización de abreviaciones crípticas como recpt y colservr. Los demás subdirectorios incluyen programas independientes que se utilizan principalmente para reforzar el proceso de creación (véase el Cuadro <tblref table_standalone_programs_included_in_greenstone>).

Otro directorio, GSDLHOME/lib, incluye objetos de nivel inferior que el recepcionista y el servidor de colección utilizan. En la Sección common_greenstone_types se explica este código.

Greenstone utiliza considerablemente la Biblioteca Estándar de Plantillas (STL), una biblioteca C++ de amplia difusión concebida por Silicon Graphics (  www.sgi.com ), y que es el resultado de numerosos años de investigación y desarrollo. Como todas las bibliotecas de programación requiere un tiempo de aprendizaje. En el Apéndice A se presenta un breve resumen de las principales porciones que se utilizan en el código de Greenstone. Para una descripción más completa, consulte el manual oficial de referencia de STL disponible en la dirección Internet  www.sgi.com , o alguno de los numerosos manuales sobre STL, como por ejemplo el de Josuttis (1999).

Tipos básicos de Greenstone

Los elementos definidos en el directorio GSDLHOME/lib son objetos Greenstone de nivel inferior, creados por encima de STL, y que se utilizan en todo el código fuente. En primer lugar, describimos con detalles text_t, un objeto utilizado para representar texto Unicode y luego resumimos la finalidad de cada uno de los archivos de biblioteca.

El objeto <i>text_t</i>

Greenstone funciona con múltiples idiomas, tanto en lo que se refiere al contenido de una colección como a la interfaz de usuario. Para ello, se utiliza Unicode a todo lo largo del código fuente. El objeto subyacente que realiza una cadena Unicode es text_t.

<imgcaption figure_the_text_t_api|%!– id:840 –%La API de text_t (abreviada) %!– withLineNumber –%></imgcaption>

typedef vector<unsigned short> usvector;
 
class text_t {
protected:
usvector text;
unsigned short encoding; // 0 = unicode, 1 = other
 
public:
  // constructors
  text_t ();
  text_t (int i);
  text_t (char *s); // assumed to be a normal c string
 
  void setencoding (unsigned short theencoding);
  unsigned short getencoding ();
 
  // STL container support
  iterator begin ();
  iterator end (); 
 
  void erase(iterator pos);
  void push_back(unsigned short c);
  void pop_back();
 
  void reserve (size_type n);
 
  bool empty () const {return text.empty();}
  size_type size() const {return text.size();}
 
  // added functionality
  void clear ();
  void append (const text_t &t);
 
  // support for integers
  void appendint (int i);
  void setint (int i);
  int getint () const;
 
  // support for arrays of chars
  void appendcarr (char *s, size_type len);
  void setcarr (char *s, size_type len);
};

Unicode necesita dos bytes para almacenar cada carácter. En la Figura <imgref figure_the_text_t_api> se muestran las características principales de la interfaz para programas de aplicación (API, esto es, Application Program Interface) de text_t. El requisito de los dos bytes se cumple utilizando el tipo estándar C++ short, que se define como un número entero de dos bytes. El principal tipo de datos del objeto text_t es una matriz dinámica de unsignedshorts elaborada mediante la declaración STL vector<unsigned short> y que recibe el nombre abreviado de usvector.

Las funciones de creación (líneas 10-12) admiten explícitamente tres formas de inicialización: creación sin parámetros, que genera una cadena Unicode vacía; creación con un parámetro entero, que genera una versión de texto Unicode con el valor numérico proporcionado; y creación con un parámetro char*, que trata el argumento como una cadena C++ terminada en cero y genera una versión Unicode del mismo.

A continuación, la mayor parte del código (líneas 17-28) se ocupa de mantener un contenedor de tipo vector STL: begin()end()push_back()empty(), etc. Permite asimismo borrar y concatenar cadenas, así como convertir un número entero en una cadena de texto Unicode y remitir el correspondiente valor entero a un texto que representa un número.

<imgcaption figure_overloaded_operators_to_text_t|%!– id:844 –%Operadores sobrecargados para text_t %!– withLineNumber –%></imgcaption>

class text_t{
      // ...
      public:
      text_t &operator=(const text_t &x);
      text_t &operator+=(const text_t &t);
      reference operator[](size_type n);
 
      text_t &operator=(int i);
      text_t &operator+= (int i);
      text_t &operator= (char *s);
      text_t &operator+= (char *s);
 
      friend inline bool operator!=(const text_t& x, const text_t& y);
      friend inline bool operator==(const text_t& x, const text_t& y);
      friend inline bool operator< (const text_t& x, const text_t& y);
      friend inline bool operator> (const text_t& x, const text_t& y);
      friend inline bool operator>=(const text_t& x, const text_t& y);
      friend inline bool operator<=(const text_t& x, const text_t& y);
      // ...
};

Existen numerosos operadores sobrecargados que no aparecen en la Figura <imgref figure_the_text_t_api>. La Figura <imgref figure_overloaded_operators_to_text_t> nos da una idea general de las operaciones posibles. La línea 4 permite asignar un objeto text_t a otro, y la línea 5 sobrecarga el operador += para poder concatenar de modo más natural un objeto text_t al final de otro. La línea 6 permite asimismo tener acceso a un carácter Unicode particular (representado como un short) utilizando subíndices de matriz [ ]. Se proporcionan asimismo operadores de asignación y concatenación para los números enteros y las cadenas C++. Las líneas 12-18 suministran operadores booleanos para comparar dos objetos text_t : igual a, diferente de, precede alfabéticamente, etc.

Existen asimismo funciones miembro que toman argumentos de tipo const en lugar de argumentos no -const, pero no se muestran aquí. Dicha repetición es habitual en los objetos C++: aumenta el volumen de la API pero sin incrementarla conceptualmente. En realidad, muchas de estas funciones se implementan como instrucciones individuales de una sola línea. Para mayor información, consulte el archivo fuente GSDLHOME/lib/text_t.h.

El código de biblioteca Greenstone

Los archivos de encabezados situados en el directorio GSDLHOME/lib comprenden una mezcla de funciones y objetos que contribuyen útilmente al sistema de ejecución de Greenstone. Cuando lo importante es la eficiencia, las funciones y las funciones miembro se especifican inline. En la mayoría de los casos, los detalles de implementación se incluyen en el archivo .cpp correspondiente al archivo de encabezados.

<tblcaption table_table|##HIDDEN##></tblcaption>

< - 100 450 >
cfgread.h Funciones de lectura y escritura de archivos de configuración. Por ejemplo, la función read_cfg_line() (leer archivo de configuración) toma como argumentos el flujo de entrada y la matriz text_tarray (abreviación de vector<text_t>) para rellenar con los datos leídos.
display.h Objeto complejo utilizado por el recepcionista para definir, almacenar y ampliar macros, y para manejar tipos. En la Sección receptionist se proporciona mayor información al respecto.
fileutil.h Auxiliar para funciones de gestión de archivos independientes del sistema operativo. Por ejemplo, filename_cat() admite hasta seis argumentos text_t y devuelve un text_t que es el resultado de concatenar los elementos utilizando el separador de directorio adecuado para el sistema operativo en cuestión.
gsdlconf.h Funciones específicas del sistema que contestan a preguntas como: ¿el sistema operativo que se está utilizando para la compilación necesita acceder al archivo  strings.h así como al archivo string.h ? ¿Se han definido correctamente todos los valores apropiados para el bloqueo de archivos?
gsdltimes.h Función de apoyo para fechas y horas. Por ejemplo, time2text() toma la hora de la computadora, expresada como el número de segundos transcurridos desde el 1º de enero de 1970, y la convierte en el formato AAAA/MM/DD hh:mm:ss, que devuelve como tipo text_t.
gsdltools.h Apoyo variado al sistema de ejecución de Greenstone: determina si se trata de littleEndian o bigEndian ; comprueba si Perl está disponible; ejecuta un comando del sistema (con “campaneos y silbidos”, esto es, con ciertas cualidades avanzadas y exageradas del programa); y elude los caracteres especiales de macro en una cadena text_t.
gsdlunicode.h Serie de objetos heredados que admiten tratar las cadenas text_t de Unicode a través de flujos de entrada y salida, como las conversiones de Unicode en UTF-8 y viceversa; y la supresión de los espacios de ancho cero. Administra asimismo los archivos de correspondencia mediante el objeto mapconvert, y carga los cuadros de correspondencia en el directorio GSDLHOME/mappings.
text_t.h Principalmente el objeto de texto de Unicode antes expuesto. Proporciona asimismo dos clases de conversión de flujos: inconvertclass y outconvertclass. Son las clases de base utilizadas en el archivo gsdlunicode.h.

El servidor de colecciones

Ahora pasaremos a explicar sistemáticamente todos los objetos del marco conceptual de la Figura <imgref figure_greenstone_runtime_system>. Empezaremos por la parte inferior del diagrama, que constituye además la base del sistema, con los objetos Búsqueda (Search), Fuente ( Source) y Filtro ( Filter), y recorreremos las capas del protocolo hasta llegar a los componentes centrales del Recepcionista, Acciones, Formato y Lenguaje de macros. Luego nos centraremos en la inicialización de los objetos, ya que es más fácil entender este proceso una vez que se conoce la función de los distintos objetos.

La mayoría de las clases fundamentales del marco conceptual se expresan mediante la herencia virtual para facilitar la extensibilidad. Mediante la herencia virtual, los objetos heredados se pueden transferir como su clase base, pero cuando se activa una función miembro, la versión definida en el objeto heredado es la que se ejecuta. Como el código fuente de Greenstone utiliza la clase base en todas partes, excepto donde se crean los objetos, esto significa que se pueden insertar fácilmente diferentes implementaciones, utilizando tal vez tecnologías subyacentes radicalmente diferentes.

Por ejemplo, supongamos que una clase de base denominada BaseCalc se encarga de la aritmética elemental: suma, resta, multiplicación y división. Si todas sus funciones se declaran virtuales, y todos los argumentos y tipos devueltos se declaran como cadenas, podemos implementar fácilmente las versiones heredadas del objeto. Una de ellas, llamada FixedPrecisionCalc, podría utilizar las funciones de la biblioteca C para las conversiones entre cadenas y números enteros e implementar los cálculos con los operadores aritméticos habituales: +, -, *,  y /. La otra, llamada InfinitePrecisionCalc, podría acceder a los argumentos de cadena carácter por carácter, efectuando operaciones aritméticas que en principio son de una precisión infinita. Escribiendo un programa principal que utiliza BaseCalc por doquier, la implementación puede pasar de la precisión finita a la precisión infinita modificando una sola línea: el lugar donde se crea el objeto de cálculo.

El objeto Búsqueda (<i>Search</i>)

<imgcaption figure_search_base_class_api|%!– id:870 –%API de la clase base Búsqueda (Search) ></imgcaption>

class searchclass {
public:
  searchclass ();
  virtual ~searchclass ();
  // the index directory must be set before any searching
  // is done 
  virtual void setcollectdir (const text_t &thecollectdir);
  // the search results are returned in queryresults
  // search returns ’true’ if it was able to do a search
  virtual bool search(const queryparamclass &queryparams,
                   queryresultsclass &queryresults)=0;
  // the document text for ’docnum’ is placed in ’output’
  // docTargetDocument returns ’true’ if it was able to
  // try to get a document
  // collection is needed to see if an index from the
  // collection is loaded. If no index has been loaded
  // defaultindex is needed to load one
  virtual bool docTargetDocument(const text_t &defaultindex,
                        const text_t &defaultsubcollection,
                        const text_t &defaultlanguage,
                        const text_t &collection,
                        int docnum,
                        text_t &output)=0;
protected:
  querycache *cache;
  text_t collectdir; // the collection directory
};

En la Figura <imgref figure_search_base_class_api> se muestra el API de la clase de base para el objeto de búsqueda de la Figura <imgref figure_greenstone_runtime_system>. Define dos funciones miembro virtuales: search() y docTargetDocument(). Tal como indica el =0 que sigue la declaración de argumento, se trata de funciones puras, lo que significa que una clase que hereda este objeto debe implementar ambas funciones (de otro modo el compilador se quejará).

La clase incluye asimismo dos campos de datos protegidos: collectdir y cache. Cuando se instancia un objeto de búsqueda para una colección particular, se utiliza el campo collectdir para determinar dónde está guardada esa colección (y, lo que es más importante, sus archivos de índice) en el sistema de archivos. El campo cache retiene el resultado de una consulta. Se utiliza para acelerar el tratamiento de consultas ulteriores que repiten la primera (y sus parámetros). Puede parecer improbable que se efectúen consultas idénticas, pero de hecho esto ocurre con bastante frecuencia. El protocolo de Greenstone es sin estado. A fin de generar una página de resultados como la de la Figura <imgref figure_searching_gutenberg_for_darcy>, pero con los resultados 11-20 de la misma consulta, se transmite de nuevo la búsqueda especificando, en este caso, que se presente la serie de documentos 11-20. El campo cache acelera esta operación, puesto que se comprueba que la búsqueda ya ha sido ejecutada y los resultados se sacan directamente de este campo.

Ambos campos de datos son aplicables a todos los objetos heredados que implementan un mecanismo de búsqueda. Por ello aparecen en la clase de base y se declaran dentro de una sección protegida de la clase, a fin de que las clases heredadas puedan acceder directamente a ellos.

Búsqueda y recuperación con MG

Greenstone utiliza MG (abreviación de Managing Gigabytes ; véase Witten et al., 1999) para indizar y recuperar documentos, y su código fuente se incluye en el directorio GSDLHOME/packages. MG emplea técnicas de compresión para optimizar la utilización del espacio de disco sin alterar la rapidez de ejecución. En el caso de una colección de documentos en inglés, el texto comprimido y los índices suelen ocupar un tercio del espacio que necesitaría el texto original sin comprimir. La búsqueda y recuperación suelen ser más rápidas que las operaciones equivalentes en la versión sin comprimir porque requieren menos operaciones en el disco duro.

<imgcaption figure_api_for_direct_access_to_mg|%!– id:876 –%API para acceder directamente a MG (abreviada) ></imgcaption>

enum result_kinds {
  result_docs,      // Return the documents found in last search
  result_docnums,   // Return document id numbers and weights
  result_termfreqs, // Return terms and frequencies
  result_terms      // Return matching query terms
};
int mgq_ask(char *line);
int mgq_results(enum result_kinds kind, int skip, int howmany,
                int (*sender)(char *, int, int, float, void *),
                void *ptr);
int mgq_numdocs(void);
int mgq_numterms(void);
int mgq_equivterms
             (unsigned char *wordstem,
              int (*sender)(char *, int, int, float, void *),
              void *ptr);
int mgq_docsretrieved (int *total_retrieved, int *is_approx);
int mgq_getmaxstemlen ();
void mgq_stemword (unsigned char *word);

MG se utiliza por lo general de manera interactiva tecleando las instrucciones desde la línea de comandos, y un modo de implementar mgsearchclass sería activando la llamada system() de la biblioteca C dentro del objeto para ejecutar los comandos MG apropiados. Sin embargo, un método más eficaz consiste en intervenir directamente en el código de MG utilizando las llamadas de función. Aunque esto requiere un mayor conocimiento del código de MG, una gran parte de la complejidad puede ocultarse tras una nueva API que pasará a ser el punto de contacto para el objeto mgsearchclass. Ésta es la función del archivo colserver/mgq.c, cuya API se muestra en la Figura <imgref figure_api_for_direct_access_to_mg>.

Para proporcionar parámetros a MG, se usa mgq_ask(), que admite opciones de texto en un formato idéntico al que se usa en la línea de comandos, como por ejemplo:

mgq_ask(“.set casefold off”);

Se utiliza asimismo para activar una consulta. Se accede a los resultados mediante la función mgq_results, que adopta como cuarto parámetro un puntero dirigido hacia una función. Ello proporciona un modo flexible de convertir la información devuelta en estructuras de datos de MG en el formato que requiere mgsearchclass. Las operaciones como mgq_numdocs()mgq_numterms() y mgq_docsretrieved() también devuelven información, pero prescritas de manera más precisa. Las dos últimas contribuyen a la función de truncamiento.

El objeto Fuente (<i>Source</i>)

<imgcaption figure_source_base_class_api|%!– id:881 –%API de la clase base Fuente (Source) ></imgcaption>

class sourceclass {
public:
  sourceclass ();
  virtual ~sourceclass ();
  // configure should be called once for each configuration line
  virtual void configure (const text_t &key, 
                          const text_tarray &cfgline);
  // init should be called after all the configuration is done but
  // before any other methods are called
  virtual bool init (ostream &logout);
  // translate_OID translates OIDs using ".pr", ."fc" etc.
  virtual bool translate_OID (const text_t &OIDin, text_t &OIDout,
                              comerror_t &err, ostream &logout);
  // get_metadata fills out the metadata if possible, if it is not
  // responsible for the given OID then it returns false.
  virtual bool get_metadata (const text_t &requestParams, 
                             const text_t &refParams,
                             bool getParents,
                             const text_tset &fields,
                             const text_t &OID,
                             MetadataInfo_tmap &metadata,
                             comerror_t &err, ostream &logout);
  virtual bool get_document (const text_t &OID, text_t &doc,
                             comerror_t &err, ostream &logout);
}; 

La función del objeto Fuente (Source) de la Figura <imgref figure_greenstone_runtime_system> es acceder a los metadatos y al texto del documento; la API de su clase de base se muestra en la Figura <imgref figure_source_base_class_api>. Una función miembro se asigna a cada tarea: las funciones get_metadata() y get_document(), respectivamente. Ambas se declaran virtual, por lo que la versión suministrada por una implementación particular de la clase de base se activa durante la ejecución. Una versión heredada de este objeto utiliza GDBM para implementar get_metadata() y MG para implementar get_document() : a continuación explicaremos en detalle esta versión.

Las otras funciones miembro que aparecen en la Figura <imgref figure_source_base_class_api> son configure()init() y translate_OID(). Las dos primeras se relacionan con el proceso de inicialización que se explica en la Sección initialisation.

La otra, translate_OID(), maneja la sintaxis para expresar los identificadores de documento. En la Figura <imgref figure_the_golf_course_mystery> vimos que el número de una página podía anexarse a un identificador de documento para recuperar únicamente esa página. Esto era posible porque, al crearse la colección, las páginas se almacenaban como “secciones”. Si se agrega “.1” a un OID, se recupera la primera sección del documento correspondiente. Las secciones pueden subdividirse y para acceder a ellas es preciso concatenar números de secciones separados por puntos.

Además de los números jerárquicos de secciones, la sintaxis del identificador de documento admite una forma de acceso relativo. En el caso de la sección en uso de un documento, se puede acceder al primer hijo anexando .fc (first child), al último niño anexando .lc (last child), al padre anexando .pr (parent), al hermanosiguiente anexando .ns(next sibling) y al hermano anterior anexando .ps (previous sibling).

La función translate_OID utiliza los parámetros OIDin y OIDout para retener la fuente y el resultado de la conversión. Incluye otros dos parámetros: err y logout. Éstos comunican cualquier estado de error que se pueda producir durante la operación de traducción, y determina dónde enviar la información de registro ( logging information). Como veremos en la Sección protocol, estos parámetros dependen estrechamente del protocolo.

Recuperación de base de datos con gdbm

GDBM es el programa de gestión de base de datos de GNU ( www.gnu.org ). Establece una estructura de registros planos de pares clave/datos, y es compatible con versiones anteriores de DBM y NDBM. Las operaciones incluyen el almacenamiento, la recuperación y la supresión de registros por clave, y un recorrido no ordenado de todas las claves.

<imgcaption figure_gdbm_database_for_the_gutenberg_collection|%!– id:889 –%La base de datos GDBM para la colección Gutenberg (extracto) ></imgcaption>

[HASH01d7b30d4827b51282919e9b]
<doctype> doc
<hastxt>           0
<Title>            The Winter’s Tale
<Creator> William Shakespeare
<archivedir>       HASH01d7/b30d4827.dir
<thistype>         Invisible
<childtype>        Paged
<contains>         ".1;".2;".3;".4;".5;".6;".7;".8;".9;".10;".11;".12; \
                 ".13;".14;".15;".16;".17;".18;".19;".20;".21;".22; \
                 ".23;".24;".25;".26;".27;".28;".29;".30;".31;".32; \
                 ".33;".34;".35
<docnum>           168483
------------------------
[CL1]
<doctype> classify
<hastxt>           0
<childtype>        HList
<Title>            Title
<numleafdocs>      1818
<thistype>         Invisible
<contains>         ".1;".2;".3;".4;".5;".6;".7;".8;".9;".10;".11;".12; \
                 ".13;".14;".15;".16;".17;".18;".19;".20;".21;".22; \
                 ".23;".24
------------------------
[CL1.1]
<doctype> classify
<hastxt>           0
<childtype>        VList
<Title>            A
<numleafdocs>      118
<contains>         HASH0130bc5f9f90089b3723431f;HASH9cba43bacdab5263c98545;\
                 HASH12c88a01da6e8379df86a7;HASH9c86579a83e1a2e4cf9736;  \
                 HASHdc2951a7ada1f36a6c3aca;HASHea4dda6bbc7cdeb4abfdee;  \
                 HASHce55006513c47235ac38ba;HASH012a33acaa077c0e612b9351;\
                 HASH010dd1e923a123826ae30e4b;HASHaf674616785679fed4b7ee;\
                 HASH0147eef4b9d1cb135e096619;HASHe69b9dbaa83ffb045d963b;\
                 HASH01abc61c646c8e7a8ce88b10;HASH5f9cd13678e21820e32f3a;\
                 HASHe8cbba1594c72c98f9aa1b;HASH01292a2b7b6b60dec96298bc;\
...

En la Figura <imgref figure_gdbm_database_for_the_gutenberg_collection> se muestra un extracto de la base de datos de informaciones de la colección elaborada durante la creación de la colección Gutenberg. El extracto se obtuvo utilizando la aplicación db2txt de Greenstone que convierte el formato binario de base de datos GDBM en forma textual. La Figura <imgref figure_gdbm_database_for_the_gutenberg_collection> contiene tres registros separados por líneas horizontales. El primero es una entrada de documento, los otros dos forman parte de la jerarquía creada por el clasificador AZList para los títulos de la colección. La primera línea de cada registro es su clave.

El registro del documento guarda el título del libro, el autor y cualquier otro metadato proporcionado (o extraído) durante la creación de la colección. Contiene asimismo valores para uso interno: dónde se encuentran los archivos asociados con ese documento (< archivedir >) y el número de documento utilizado internamente por MG (< docnum >).

En el campo < contains > se almacena una lista de elementos, separados por caracteres de punto y coma, que remiten a registros conexos en la base de datos. Para un registro de documento, el campo < contains > sirve para señalar las secciones subdivididas. Las subsiguientes claves de registro se forman concatenando la clave en curso con uno de los elementos secundarios (separado por un punto).

El segundo registro de la Figura <imgref figure_gdbm_database_for_the_gutenberg_collection> es el nodo principal de la jerarquía de clasificación de t ítulos a-z. Sus elementos secundarios, a los que se accede a través del campo < contains >, incluyen CL1.1CL1.2CL1.3 y así sucesivamente, y corresponden a las distintas páginas para las letras ABC, etc. Hay únicamente 24 elementos secundarios: el clasificador AZList fusionó las letras Q-R e Y-Z porque sólo incluían unos cuantos títulos.

Los elementos secundarios en el campo < contains > del tercer registro, CL1.1, son los documentos propiamente dichos. Es posible establecer estructuras más complicadas: el campo < contains > puede incluir una combinación de documentos y otros nodos CL. Las claves relacionadas con la clave en curso se distinguen de las claves absolutas porque llevan comillas (“) antepuestas.

El uso de MG y GDBM para implementar un objeto Fuente (Source)

<imgcaption figure_api_for_mg_and_gdbm_based_version_of_sourceclass|%!– id:896 –%API de la versión de sourceclass basada en MG y GDBM (abreviada) ></imgcaption>

class mggdbmsourceclass : public sourceclass {
protected:
  // Omitted, data fields that store:
  //   collection specific file information
  //   index substructure
  //   information about parent
  //   pointers to gdbm and mgsearch objects
public:
  mggdbmsourceclass ();
  virtual ~mggdbmsourceclass ();
  void set_gdbmptr (gdbmclass *thegdbmptr);
  void set_mgsearchptr (searchclass *themgsearchptr);
  void configure (const text_t &key, const text_tarray &cfgline);
  bool init (ostream &logout);
  bool translate_OID (const text_t &OIDin, text_t &OIDout,
                      comerror_t &err, ostream &logout);
  bool get_metadata (const text_t &requestParams,
                       const text_t &refParams,
                       bool getParents, const text_tset &fields,
                       const text_t &OID, MetadataInfo_tmap &metadata,
                       comerror_t &err, ostream &logout);
  bool get_document (const text_t &OID, text_t &doc,
                     comerror_t &err, ostream &logout);
};

El objeto que reúne MG y GDBM para efectuar una implementación de sourceclass se denomina mggdbmsourceclass. En la Figura <imgref figure_api_for_mg_and_gdbm_based_version_of_sourceclass> se presenta su API. Las dos nuevas funciones miembro set_gdbmptr() y set_mgsearchptr() almacenan punteros dirigidos hacia sus respectivos objetos, de modo que las implementaciones de get_metadata() y get_document() puedan acceder a las herramientas apropiadas para llevar a cabo su tarea.

El objeto Filtro (<i>Filter</i>)

<imgcaption figure_api_for_the_filter_base_class|%!– id:899 –%API de la clase base de Filtro ></imgcaption>

class filterclass {
protected:
  text_t gsdlhome;
  text_t collection;
  text_t collectdir;
  FilterOption_tmap filterOptions;
public:
  filterclass ();
  virtual ~filterclass ();
  virtual void configure (const text_t &key,
                          const text_tarray &cfgline);
  virtual bool init (ostream &logout);
  // returns the name of this filter
  virtual text_t get_filter_name ();
  // returns the current filter options
  virtual void get_filteroptions
                                (InfoFilterOptionsResponse_t &response, 
                                 comerror_t &err, ostream &logout);
  virtual void filter (const FilterRequest_t &request,
                       FilterResponse_t &response,
                       comerror_t &err, ostream &logout);
};

La API de la clase de base para el objeto Filtro de la Figura <imgref figure_greenstone_runtime_system> se presenta en la Figura <imgref figure_api_for_the_filter_base_class>. Empieza con los campos de datos protegidos gsdlhomecollection y collectdir. Estos suelen emplearse en las clases que necesitan acceder a archivos de colecciones específicas:

  • gsdlhome es lo mismo que GSDLHOME, de modo que el objeto pueda localizar los archivos de Greenstone
  • collection es el nombre del directorio que corresponde a la colección
  • collectdir es el nombre de ruta completo del directorio de la colección (es necesario porque una colección no tiene por qué encontrarse necesariamente en la zona GSDLHOME).

mggdbsourceclass es otra clase que incluye estos tres campos de datos.

El proceso de inicialización utiliza las funciones miembro configure() e init() (que ya vimos en la función sourceclass). El propio objeto se alinea estrechamente con la porción de filtro que le corresponde en el protocolo; las funciones get_filteroptions() y filter(), en particular, coinciden exactamente.

<imgcaption figure_how_a_filter_option_is_stored|%!– id:906 –%Manera en que se almacena una opción de filtro ></imgcaption>

struct FilterOption_t {
  void clear (); \ void check_defaultValue ();
  FilterOption_t () {clear();}
  text_t name;
  enum type_t {booleant=0, integert=1, enumeratedt=2, stringt=3};
  type_t type;
  enum repeatable_t {onePerQuery=0, onePerTerm=1, nPerTerm=2};
  repeatable_t repeatable;
  text_t defaultValue; 
  text_tarray validValues;
};
struct OptionValue_t {
  void clear ();
  text_t name;
  text_t value;
};

Las dos clases que se muestran en la Figura <imgref figure_how_a_filter_option_is_stored> son fundamentales para las opciones de filtro. FilterOption_t almacena el nombre (name) de la opción, su tipo (type), y si se puede repetir o no ( repeatable). La interpretación de validValues depende del tipo de opción. Para un tipo booleano, el primer valor es false y el segundo true. Para un tipo entero, el primer valor es el número mínimo y el segundo el máximo. Para un tipo enumerado todos los valores están en la lista. Para un tipo de cadena se ignora el valor. Para las situaciones más simples, se emplea OptionValue_t que registra el nombre de la opción y su valor como text_t.

Los objetos de búsqueda y de respuesta transmitidos como parámetros a filterclass se crean a partir de estas dos clases, utilizando matrices asociativas para almacenar un conjunto de opciones como las que se requieren para InfoFilterOptionsResponse_t. Para obtener más detalles véase GSDLHOME/src/recpt/comtypes.h.

Objetos Filtro heredados (<i>Inherited Filter</i>)

<imgcaption figure_inheritance_hierarchy_for_filter|%!– id:910 –%Jerarquía de herencia para el objeto de filtro ></imgcaption>

Tal como se muestra en la Figura <imgref figure_inheritance_hierarchy_for_filter>, los filtros utilizan dos niveles de herencia. En primer lugar, se establece una distinción entre filtros de búsqueda y consulta, y luego para los primeros se procede a una implementación específica basada en MG. Para que funcione correctamente, mgqueryfilterclass necesita acceder a MG a través de mgsearchclass y a GDBM a través de gdbmclassbrowsefilterclass sólo necesita tener acceso a GDBM. Los punteros de estos objetos se guardan como campos de datos protegidos dentro de las respectivas clases.

El código del servidor de colección

A continuación presentamos los archivos de encabezado del directorio GSDLHOME/src/colservr. El nombre del archivo coincide por lo general con el nombre del objeto que define.

<tblcaption table_table_1|##HIDDEN##></tblcaption>

< - 120 420 >
browsefilter.h Heredado de filterclass, este objeto proporciona acceso a GDBM (se explica más arriba).
collectserver.h Este objeto enlaza los objetos Filtro y de Fuente de una colección a fin de formar el objeto Colección representado en la Figura <imgref figure_greenstone_runtime_system>.
colservrconfig.h Función de apoyo para la lectura de los archivos específicos de una colección etc/collect.cfg e index/build.cfg. El primero es el archivo de configuración de la colección y el segundo es un archivo generado por el proceso de creación que registra la hora de la última creación llevada satisfactoriamente a cabo, una lista de las correspondencias de índice, el número de documentos indizados y su tamaño en bytes (sin comprimir).
filter.h La clase de base del objeto de filtro filterclass antes mencionado.
maptools.h Define una clase llamada stringmap que proporciona una correspondencia que recuerda el orden original de una correspondencia text_t, pero cuya consulta es rápida. Se utiliza en mggdbmsourceclass y queryfilterclass.
mggdbmsource.h Heredado de sourceclass, este objeto proporciona acceso a MG y GDBM (se explica más arriba).
mgppqueryfilter.h Heredado de queryfilterclass, este objeto proporciona una implementación de QueryFilter basada en MG++, una versión mejorada de MG escrita en C++. Obsérvese que Greenstone está configurado para utilizar MG por defecto, ya que MG++ se encuentra todavía en fase de desarollo.
mgppsearch.h Heredado de searchclass, este objeto proporciona une implementación del objeto Búsqueda utilizando MG++. Como mgppqueryfilterclass, tampoco se utiliza por defecto.
mgq.h Interfaz funcional para el paquete MG. Sus principales funciones son mg_ask() y mg_results().
mgqueryfilter.h Heredado de queryfilterclass, este objeto proporciona una implementación de QueryFilter basada en MG.
mgsearch.h Heredado de searchclass, este objeto proporciona una implementación de Search <i/> (búsqueda) utilizando MG (se explica más arriba).
phrasequeryfilter.h Heredado de mgqueryclass, este objeto proporciona una clase de consulta basada en frases. No se utiliza en la instalación por defecto. En su lugar mgqueryfilterclass ofrece esta posibilidad a través del apoyo funcional de phrasesearch.h.
phrasesearch.h Función de apoyo para efectuar una búsqueda de grupos de palabras como operación posterior al tratamiento.
querycache.h Utilizado por searchclass y sus clases heredadas para almacenar en el campo caché los resultados de una consulta, a fin de que la generación de las páginas resultantes de búsquedas posteriores resulte más eficaz (se explica más arriba).
queryfilter.h Heredado de la clase base de filtro filterclass, este objeto establece una clase base para los objetos Filtro y Búsqueda (se explica más arriba).
queryinfo.h Ayuda para la búsqueda: estructuras de datos y objetos para guardar los parámetros de consulta, los resultados de documentos y las frecuencias de términos.
search.h La clase de base del objeto Búsqueda searchclass (se explica más arriba).
source.h La clase de base del objeto Fuente sourceclass (se explica más arriba).

Protocolo

<tblcaption table_list_of_protocol_calls|Lista de llamadas del protocolo></tblcaption>

< - 132 397 >
get_protocol_name() Devuelve el nombre de este protocolo. Las opciones incluyen nullprotocorbaproto y z3950proto. Utilizado por las partes del sistema de ejecución que dependen del protocolo para decidir qué código ejecutar.
get_collection_list() Devuelve la lista de colecciones que este protocolo conoce.
has_collection() Devuelve el valor true ( verdadero) si el protocolo puede comunicar con la colección nombrada, es decir, si se encuentra en su lista de colecciones.
ping() Reenvía el valor true (verdadero) si se ha logrado establecer una conexión con la colección nombrada. En el caso del protocolo nulo, la implementación es idéntica a la de has_collection().
get_collectinfo() Obtiene información general sobre la colección nombrada: fecha de la última creación, número de documentos que contiene, etc. Incluye también metadatos del archivo de configuración de la colección: texto de “Acerca de esta colección”, el icono de la colección que ha de utilizarse, etc.
get_filterinfo() Obtiene una lista de todos los objetos Filtro para la colección nombrada.
get_filteroptions() Obtiene todas las opciones para un objeto Filtro particular en la colección nombrada.
filter() Permite la búsqueda y la consulta. Para un tipo de filtro determinado y unas configuraciones de opciones, accede al contenido de las colecciones nombradas para producir un conjunto de resultados que es filtrado según las configuraciones de opciones. Los campos de datos devueltos dependen también de las configuraciones de opciones, por ejemplo: la frecuencia de los términos de consulta y los metadatos de documento.
get_document() Obtiene un documento o sección de un documento.

En el Cuadro <tblref table_list_of_protocol_calls> se presenta una lista de las llamadas de función al protocolo, y un resumen de cada una de ellas. Los ejemplos de la Sección how_the_conceptual_framework_fits_together ilustran la mayoría de esas llamadas. Las funciones no mencionadas anteriormente son has_collection()ping()get_protocol_name() y get_filteroptions(). Las dos primeras responden afirmativa o negativamente a las preguntas “¿existe la colección en este servidor?” y “¿se encuentra en funcionamiento?”, respectivamente. La finalidad de las otras dos es admitir protocolos múltiples en una arquitectura repartida en diferentes computadoras, y no sólo el ejecutable individual basado en el protocolo nulo que se menciona aquí. Una de ellas detecta qué protocolo se encuentra en uso. La otra permite que un recepcionista consulte al servidor de una colección para averiguar qué opciones admite, a fin de configurarse dinámicamente y sacar el máximo provecho de los servicios ofrecidos por un servidor particular.

<imgcaption figure_null_protocol_api|%!– id:971 –%API del protocolo nulo (abreviado) ></imgcaption>

class nullproto : public recptproto {
public:
  virtual text_t get_protocol_name ();
  virtual void get_collection_list (text_tarray &collist,
                        comerror_t &err, ostream &logout);
  virtual void has_collection (const text_t &collection,
                        bool &hascollection,
                        comerror_t &err, ostream &logout);
  virtual void ping (const text_t &collection,
                        bool &wassuccess,
                        comerror_t &err, ostream &logout);
  virtual void get_collectinfo (const text_t &collection,
                        ColInfoResponse_t &collectinfo, 
                        comerror_t &err, ostream &logout);
virtual void get_filterinfo (const text_t &collection,
                        InfoFiltersResponse_t &response,
                        comerror_t &err, ostream &logout);
virtual void get_filteroptions (const text_t &collection,
                        const InfoFilterOptionsRequest_t &request,
                        InfoFilterOptionsResponse_t &response,
                        comerror_t &err, ostream &logout);
  virtual void filter (const text_t &collection,
                       FilterRequest_t &request,
                       FilterResponse_t &response,
                       comerror_t &err, ostream &logout);
  virtual void get_document (const text_t &collection,
                             const DocumentRequest_t &request,
                             DocumentResponse_t &response,
                             comerror_t &err, ostream &logout);
};

En la Figura <imgref figure_null_protocol_api> se muestra la API para el protocolo nulo. Se han omitido los comentarios y determinados detalles de nivel inferior (véase el archivo fuente recpt/nullproto.h para obtener más información al respecto).

Este protocolo hereda de la clase de base recptproto. Se utiliza la herencia virtual a fin de poder admitir fácilmente más de un tipo de protocolo –incluso protocolos aún no concebidos– en el resto del código fuente. Ello es posible porque el objeto de clase de base recptproto se utiliza a lo largo de todo el código fuente, excepto en el punto de creación, donde especificamos la variedad concreta de protocolo que deseamos utilizar que, en este caso, es el protocolo nulo.

Con la excepción de get_protocol_name(), que no toma parámetros y devuelve el nombre del protocolo como una cadena de texto codificada en Unicode, todas las funciones de protocolo incluyen un parámetro de error y un flujo de salida como argumentos finales. El parámetro de error registra cualquier error que se produce durante la ejecución de la llamada de protocolo y la secuencia de salida se utiliza a efectos de registro ( logging). Las funciones son del tipo void, esto es, no reenvían explícitamente la información en su instrucción final, sino que reenvían datos a través de parámetros designados como el parámetro de error antes mencionado. En algunos lenguajes de programación, estos subprogramas se definirían como “procedimientos” en vez de “funciones”, pero C++ no establece ninguna distinción sintáctica.

La mayoría de las funciones toman el nombre de la colección como argumento. Tres de las funciones miembro, get_filteroptions()filter() y get_document() siguen el esquema de proporcionar un parámetro de consulta y de recibir los resultados en un parámetro de respuesta Response.

El recepcionista

La capa final del modelo conceptual es el recepcionista. Una vez analizados los argumentos CGI, la actividad principal es la ejecución de una acción con la asistencia de los objetos Formato y Lenguaje de macros, que se explican más adelante. Aunque se representen como objetos en el marco conceptual, los objetos Formato y Lenguaje de macros no son estrictamente objetos en el sentido de C++. En realidad, el objeto de formato es una colección de estructuras de datos con un conjunto de funciones que operan en aquéllas, y el objeto de lenguaje de macros se crea en torno a displayclass, definido en lib/display.h con un apoyo de conversión de flujo procedente de lib/gsdlunicode.h.

Acciones

<tblcaption table_actions_in_greenstone|Las acciones en Greenstone></tblcaption>

< - 132 397 >
action Clase base para la herencia virtual.
authenaction Presta ayuda a la autenticación del usuario: pide al usuario una contraseña si no se ha introducido ninguna, comprueba su validez y obliga al usuario a introducir la contraseña de nuevo si transcurre demasiado tiempo entre dos accesos.
collectoraction Genera las páginas para el Colector.
documentaction Recupera documentos, secciones de documentos, porciones de la jerarquía de clasificación o información sobre formatos.
extlinkaction Lleva un usuario directamente a una dirección URL que es externa a la colección, generando eventualmente antes una página de alerta (según las preferencias).
pageaction Genera una página en conjunción con el lenguaje de macros.
pingaction Comprueba si una colección está en línea.
queryaction Efectúa una búsqueda.
statusaction Genera las páginas de administración.
tipaction Facilita de forma aleatoria una sugerencia al usuario.
usersaction Administra la adición, la supresión y la gestión de los accesos de usuario.

Greenstone admite las once acciones que se resumen en el Cuadro <tblref table_actions_in_greenstone>.

<imgcaption figure_using_the_cgiargsinfoclass_from_pageactioncpp|%!– id:1003 –%Utilización de cgiargsinfoclass desde pageaction.cpp %!– withLineNumber –%></imgcaption>

cgiarginfo arg_ainfo;
arg_ainfo.shortname = "a";
arg_ainfo.longname = "action";
arg_ainfo.multiplechar = true;
arg_ainfo.argdefault = "p";
arg_ainfo.defaultstatus = cgiarginfo::weak;
arg_ainfo.savedarginfo = cgiarginfo::must;
argsinfo.addarginfo (NULL, arg_ainfo);
 
arg_ainfo.shortname = "p";
arg_ainfo.longname = "page";
arg_ainfo.multiplechar = true;
arg_ainfo.argdefault = "home";
arg_ainfo.defaultstatus = cgiarginfo::weak;
arg_ainfo.savedarginfo = cgiarginfo::must;
argsinfo.addarginfo (NULL, arg_ainfo);

Los argumentos CGI necesarios para una acción se declaran formalmente en la función constructora utilizando cgiarginfo (definida en recpt/cgiargs.h). En la Figura <imgref figure_using_the_cgiargsinfoclass_from_pageactioncpp> se muestra un extracto de la función constructora pageaction, que define el tamaño y las propiedades de los argumentos CGI a y p.

Para cada argumento CGI, el constructor debe especificar su nombre corto (líneas 2 y 10), que es el nombre de la variable CGI propiamente dicha; un nombre largo (líneas 3 y 11) que se utiliza para proporcionar una descripción más elocuente de la acción; si representa un valor de carácter simple o múltiple (líneas 4 y 12); un posible valor por defecto (líneas 5 y 13); lo que ocurre cuando se proporcionan varios valores por defecto (líneas 6 y 14) (ya que pueden introducirse valores por defecto en los archivos de configuración); y si es preciso preservar o no el valor al final de esta acción (líneas 7 y 15).

Puesto que está integrada en el código, se pueden generar automáticamente páginas Web que detallan esta información. La acción statusaction produce esta información, que puede visualizarse introduciendo la dirección URL de la página de administración de Greenstone.

Las doce acciones heredadas se construyen en main(), la función de alto nivel del ejecutable library, cuya definición figura en el archivo recpt/librarymain.cpp. Es aquí también donde se forma el objeto Recepcionista (definido en recpt/receptionist.cpp). La responsabilidad de todas las acciones recae en el objeto de recepcionista, que las trata manteniendo, como un campo de datos, una matriz asociativa de la clase base Acción, indizada por nombres de acción.

<imgcaption figure_action_base_class_api|%!– id:1008 –%API de la clase base Acción ></imgcaption>

class action {
protected:
  cgiargsinfoclass argsinfo;
  text_t gsdlhome;
public:
  action ();
  virtual ~action ();
  virtual void configure (const text_t &key,
                          const text_tarray &cfgline);
  virtual bool init (ostream &logout);
  virtual text_t get_action_name ();
  cgiargsinfoclass getargsinfo ();
  virtual bool check_cgiargs (cgiargsinfoclass &argsinfo,
                              cgiargsclass &args,
                              ostream &logout);
virtual bool check_external_cgiargs (cgiargsinfoclass &argsinfo,
                              cgiargsclass &args,
                              outconvertclass &outconvert,
                              const text_t &saveconf,
                              ostream &logout); 
virtual void get_cgihead_info (cgiargsclass &args,
                              recptprotolistclass *protos,
                              response_t &response,
                              text_t &response_data,
                              ostream &logout);
virtual bool uses_display (cgiargsclass &args);
virtual void define_internal_macros (displayclass &disp,
                              cgiargsclass &args,
                              recptprotolistclass *protos,
                              ostream &logout);
virtual void define_external_macros (displayclass &disp,
                              cgiargsclass &args,
                              recptprotolistclass *protos,
                              ostream &logout);
virtual bool do_action (cgiargsclass &args,
                        recptprotolistclass *protos,
                        browsermapclass *browsers,
                        displayclass &disp,
                        outconvertclass &outconvert,
                        ostream &textout,
                        ostream &logout);
};

En la Figura <imgref figure_action_base_class_api> se muestra la API de la clase base Acción. Cuando se ejecuta una acción, el objeto Recepcionista activa diversas funciones, empezando por check_cgiarsgs(). La mayoría de estas funciones contribuyen a verificar, configurar y definir valores y macros, mientras que do_action() genera efectivamente la página resultante. Si un objeto heredado particular no dispone de una definición para una función miembro determinada, pasa a la definición de la clase base que implementa un comportamiento por defecto apropiado.

La explicación de las funciones miembro es la siguiente:

  • get_action_name() devuelve el valor del argumento CGI a que especifica esta acción. El nombre debería ser corto pero puede incluir más de un carácter.
  • check_cgiargs() es llamada antes que get_cgihead_info()define_external_macros() y do_action(). En caso de error aparece un mensaje escrito en logout ; si el error es importante, la función devuelve el valor false (falso) y no genera ningún contenido de página.
  • check_external_cgiargs() se activa después de check_cgiargs() para todas las acciones. Su uso se limita a invalidar otros comportamientos por defecto, como por ejemplo, mostrar una página de conexión cuando la página solicitada requiere una autenticación.
  • get_cgihead_info() establece la información del encabezado CGI. Si response tiene el valor de location, entonces response_data contiene la dirección de redirección. Si response equivale a content, entonces response_data contiene el tipo de contenido.
  • uses_display() devuelve true ( verdadero) si se necesita displayclass para mostrar el contenido de la página (comportamiento por defecto).
  • define_internal_macros() define todas las macros relacionadas con las páginas generadas por esta acción.
  • define_external_macros() define todas las macros que podrían ser utilizadas por otras acciones para producir páginas.
  • do_action() genera la página resultante, normalmente en un flujo a través del objeto Lenguaje de macros display y el objeto de conversión de salida textout. Reenvía el valor false si un error ha impedido que la acción produzca un resultado.

Situado en el principio de la definición de clase, argsinfo es el campo de datos protegidos (utilizado en el extracto de código que se muestra en la Figura <imgref figure_using_the_cgiargsinfoclass_from_pageactioncpp>) que almacena la información de argumento CGI especificada en una función constructora de acción heredada. El otro campo de datos, gsdlhome, registra GSDLHOME para facilitar el acceso1). El objeto incluye asimismo las funciones configure() e init() a efectos de inicialización.

Formateo

<imgcaption figure_core_data_structures_in_format|%!– id:1021 –%Estructuras de datos centrales de la clase Formato ></imgcaption>

enum command_t {comIf, comOr, comMeta, comText, comLink, comEndLink,
                comNum, comIcon, comDoc,
                comHighlight, comEndHighlight};
enum pcommand_t {pNone, pImmediate, pTop, pAll};
enum dcommand_t {dMeta, dText};
enum mcommand_t {mNone, mCgiSafe};
struct metadata_t {
  void clear();
  metadata_t () {clear();}
  text_t metaname;
  mcommand_t metacommand;
  pcommand_t parentcommand;
  text_t parentoptions;
};
// The decision component of an {If}{decision,true-text,false-text}
// formatstring. The decision can be based on metadata or on text;
// normally that text would be a macro like
// _cgiargmode_.
struct decision_t {
  void clear();
  decision_t () {clear();}
  dcommand_t command;
  metadata_t meta;
  text_t text;
};
struct format_t {
  void clear();
  format_t () {clear();}
  command_t command;
  decision_t decision;
  text_t text;
  metadata_t meta;
  format_t *nextptr;
  format_t *ifptr;
  format_t *elseptr;
  format_t *orptr;
};

Aunque en la Figura <imgref figure_greenstone_runtime_system> el formateo se representa como una entidad única, en realidad está constituida por un conjunto de estructuras de datos y funciones, que se encuentran en el archivo de encabezado recpt/formattools.h. Las estructuras de datos centrales aparecen en la Figura <imgref figure_core_data_structures_in_format>.

<imgcaption figure_data_structures_built_for_sample_format_statement|%!– id:1023 –%Estructuras de datos creadas para el ejemplo de instrucción de formato ></imgcaption>

Es más fácil explicar la implementación con un ejemplo. Cuando la instrucción de formato:

       Format CL1Vlist
“[link][Title]{If}{[Creator], por [Creator]}[/link]}”

es leída desde un archivo de configuración de colección, las funciones de formattools.cpp la analizan y se forma la estructura de datos interconectados que se muestra en la Figura <imgref figure_data_structures_built_for_sample_format_statement>. Cuando es necesario que una acción evalúe la instrucción de formato, se recorre la estructura de datos. La ruta que se toma a nivel de los nodos comIf y comOr depende de los metadatos devueltos por una llamada al protocolo.

Al recuperar los metadatos, puede ocurrir que el resultado contenga otras macros y sintaxis de formato. Esto se resuelve avanzando y retrocediendo entre el análisis y la evaluación, según convenga.

El lenguaje de macros

La entidad de Lenguaje de macros de la Figura <imgref figure_greenstone_runtime_system>, al igual que la de Formato, no corresponde a una única clase C++. En este caso existe una clase principal, pero la implementación del lenguaje de macros depende también de funciones y clases de apoyo.

La mejor manera de explicarlo es, una vez más, mediante un ejemplo. En primer lugar presentaremos unos ejemplos de definiciones de macros que ilustran las prioridades de las macros, luego, mediante un diagrama, describiremos las estructuras de datos principales creadas para apoyar esta actividad. Por último, presentaremos y explicaremos las funciones miembro públicas de displayclass, el objeto de macro de primer nivel.

<imgcaption figure_illustration_of_macro_precedence|%!– id:1031 –%Ilustración de la prioridad entre las macros ></imgcaption>

package query
_header_ []                           {_querytitle_}
_header_ [l=en]                       {Search page}
_header_ [c=demo]           {<table
bgcolor=green><tr><td>_querytitle_</td></tr></table>}
_header_ [v=1]                        {_textquery_}
_header_ [l=fr,v=1,c=hdl]   {HDL Page de recherche}

En una colección Greenstone clásica, la prioridad entre las macros es normalmente: c (para la colección) tiene prioridad sobre v (para la interfaz gráfica o textual), que tiene prioridad sobre l (para el idioma). Esto se establece con la línea:

macroprecedence c, v, l

en el archivo de configuración principal main.cfg. Las instrucciones de macros de la Figura <imgref figure_illustration_of_macro_precedence> definen ejemplos de macros para _ header _ en el paquete query para distintos valores de cv y l. Si los argumentos CGI proporcionados cuando se solicita una acción incluyen c=hdlv=1 y l=en, se seleccionaría entonces la presentación de la macro _ header _ [v=1]. Se seleccionaría antes que _ content _ [l=en] porque v tiene prioridad sobre l. La macro _ content _ [l=fr, v=1, c=hdl] no sería seleccionada porque el parámetro de página para l es diferente.

<imgcaption figure_data_structures_representing_the_default_macros|%!– id:1034 –%Estructuras de datos que representan las macros por defecto ></imgcaption>

En la Figura <imgref figure_data_structures_representing_the_default_macros> se muestra la estructura de datos principales creada por la lectura de los archivos de macros especificados en etc/main.cfg. Se trata esencialmente de una matriz asociativa de matrices asociativas de matrices asociativas. El nivel superior (que aparece a la izquierda) indiza el paquete del que procede la macro, y el segundo nivel indiza el nombre de la macro. El último nivel indiza todos los parámetros especificados, guardando cada uno de ellos como tipo mvalue que registra el valor de la macro y el archivo del que procede. Por ejemplo, podemos ver el texto definido para _ header _ [l=en] de la Figura <imgref figure_illustration_of_macro_precedence> almacenado en el más bajo de los dos registros mvalue de la Figura <imgref figure_data_structures_representing_the_default_macros>.

<imgcaption figure_displayclass_api|%!– id:1036 –%API de la clase displayclass (abreviada) ></imgcaption>

class displayclass
{
public:
  displayclass ();
  ~displayclass ();
  int isdefaultmacro (text_t package, const text_t &macroname);
  int setdefaultmacro (text_t package, const text_t &macroname,
                       text_t params, const text_t &macrovalue); 
  int loaddefaultmacros (text_t thisfilename);
  void openpage (const text_t &thispageparams,
  const text_t &thisprecedence);
  void setpageparams (text_t thispageparams,
                      text_t thisprecedence);
  int setmacro (const text_t &macroname,
                text_t package,
                const text_t &macrovalue);
  void expandstring (const text_t &inputtext, text_t &outputtext);
  void expandstring (text_t package, const text_t &inputtext,
                     text_t &outputtext, int recursiondepth = 0);
  void setconvertclass (outconvertclass *theoutc) {outc = theoutc;}
                        outconvertclass *getconvertclass () {return outc;}
                        ostream *setlogout (ostream *thelogout);
};

El objeto principal de apoyo al lenguaje de macros es displayclass, definido en lib/display.h. Sus funciones miembro públicas aparecen en la Figura <imgref figure_displayclass_api>. La clase lee los archivos de macros especificados utilizando loaddefaultmacros() y guarda en una sección protegida de la clase (que no se muestra) el tipo de la estructura de datos que se muestra en la Figura <imgref figure_data_structures_representing_the_default_macros>. Es posible asimismo que el sistema de ejecución cree macros utilizando setmacro() (en el último ejemplo de la Sección how_the_conceptual_framework_fits_togetherpageaction establece que _ homeextra _ sea el cuadro generado dinámicamente para las colecciones disponibles que utilizan esta función). Todo ello con la ayuda de un conjunto de matrices asociativas semejantes a las que se utilizan para representar los archivos de macros (no es idéntico porque el primero no requiere la capa “parámetro”). En displayclass, las macros que se leen desde el archivo se denominan macros por defecto. Las macros locales que se especifican a través de setmacro() se denominan macros en curso, y son borradas de la memoria tras generarse la página.

Cuando se va a generar una página, se llama primero openpage() para comunicar las configuraciones en curso de los parámetros de la página en cuestión ( l=en, etc.). A continuación, el texto y las macros fluyen a través de la clase – normalmente desde una actionclass – utilizando el código:

cout << text_t2ascii << display << “_unamacro_”
                                << “_otramacro_”;

El resultado es que las macros se amplían siguiendo las configuraciones de los parámetros de la página. En caso necesario, estas configuraciones pueden modificarse durante el proceso mediante una acción que utiliza setpageparams(). Las demás funciones miembro públicas proporcionan el apoyo de nivel inferior.

El código del recepcionista

Hemos explicado ya los objetos principales del recepcionista. A continuación, detallaremos las clases de apoyo que se encuentran en el directorio GSDLHOME/src/recpt. Excepto cuando la eficiencia es prioritaria, en cuyo caso las definiciones están inline (en línea), los detalles de la implementación se encuentran en el archivo .cpp correspondiente al archivo de encabezados. Los archivos de apoyo suelen incluir la palabra tool como parte del nombre del archivo, como en OIDtools.h y formattools.h.

Un segundo conjunto de archivos de alcance léxico comprenden el prefijo z3950. Los archivos proporcionan acceso remoto a las bases de datos y los catálogos en línea públicamente accesibles mediante el protocolo Z39.50.

Otro amplio grupo de archivos de apoyo comprende el término browserclass. Estos archivos están relacionados mediante una jerarquía de herencia virtual. Como grupo apoyan la noción abstracta de consulta: generación de páginas en serie que comportan contenidos de documentos compartimentados o metadatos. Las posibilidades de consulta incluyen el examen de documentos ordenados alfabéticamente por título o cronológicamente por fecha, la consulta de los resultados de una búsqueda por grupos de diez, y el acceso a las páginas individuales de un libro utilizando el mecanismo “ir a la página”. Todas las actividades de consulta heredan la clase de base browserclass :

  • datelistbrowserclass para apoyo para las listas cronológicas;
  • hlistbrowserclass para apoyo para las listas horizontales;
  • htmlbrowserclass para apoyo para las páginas HTML;
  • invbrowserclass para apoyo para las listas invisibles;
  • pagedbrowserclass para apoyo para ir a una página particular;
  • vlistbrowserclass para apoyo para las listas verticales.

Las acciones acceden a los objetos browserclass a través del archivo browsetools.h.

<tblcaption table_table_2|##HIDDEN##></tblcaption>

< - 140 390 >
OIDtools.h Función de apoyo para la evaluación de los identificadores de documento en el protocolo.
action.h Clase de base para la entidad Acción expuesta en la Figura <imgref figure_greenstone_runtime_system>.
authenaction.h Acción heredada para la gestión de la autenticación de un usuario.
browserclass.h Clase de base para las actividades de consulta abstractas.
browsetools.h Función de apoyo para el acceso a la jerarquía browserclass. Las funciones incluyen la ampliación y contracción de contenidos, la creación de un índice y la generación de controles como el mecanismo “ir a la página”.
cgiargs.h Define cgiarginfo, utilizado en la Figura <imgref figure_using_the_cgiargsinfoclass_from_pageactioncpp>, así como el apoyo de otras estructuras de datos para los argumentos CGI.
cgiutils.h Función de apoyo para los argumentos CGI que utilizan las estructuras de datos definidas en cgiargs.h.
cgiwrapper.h Función de apoyo que hace todo lo necesario para generar una página utilizando el protocolo CGI. El acceso se hace mediante la función:
void cgiwrapper (receptionist &recpt,
text_t collection);
que es la única función declarada en el archivo de encabezados. Todo el resto del archivo .cpp tiene un alcance léxico de carácter local en el archivo (utilizando la palabra clave C++ static). Si se utiliza la función para una colección particular, entonces se debe introducir collection, o si no la cadena vacía “”. El código incluye apoyo para Fast-CGI.
collectoraction.h Acción heredada que facilita la creación de colecciones por parte del usuario final mediante el Colector. La página generada procede de collect.dm y es controlada por el argumento CGI p=page.
comtypes.h Tipos centrales del protocolo.
converter.h Objeto de apoyo para los convertidores de flujo.
datelistbrowserclass.h Heredado de browserclass, este objeto presta apoyo para la consulta de las listas cronológicas, como las que se ven en la colección Archivos Greenstone en “ dates ” (fechas) de la barra de desplazamiento.
documentaction.h Acción heredada que se utiliza para recuperar un documento o porción de una jerarquía de clasificación.
extlinkaction.h Acción heredada que controla si un usuario va directamente a un enlace externo o si debe pasar por una página de aviso que le informa de que se dispone a salir del sistema de biblioteca digital.
formattools.h Función de apoyo para analizar y evaluar las instrucciones format de configuración de colección. Se explica con más detalles en la Sección formatting supra.
historydb.h Estructuras de datos y función de apoyo para la gestión de una base de datos de búsquedas anteriores, de modo que un usuario pueda iniciar una nueva búsqueda que incluya términos de búsquedas anteriores.
hlistbrowserclass.h Heredado de browserclass, este objeto presta apoyo para la consulta de las listas horizontales.
htmlbrowserclass.h Heredado de browserclass, este objeto presta apoyo para la consulta de las páginas HTML.
htmlgen.h Función de apoyo para resaltar los términos de búsqueda en una cadena text_t.
htmlutils.h Función de apoyo que convierte una cadena text_t en el HTML equivalente. Los símbolos “, &, < y > se convierten respectivamente en &quot;&amp;&lt; y &gt;.
infodbclass.h Define dos clases: gdbmclass e infodbclass. La primera proporciona la API de Greenstone para GDBM; la segunda es la clase de objeto utilizada para guardar una entrada de registro leída en una base de datos GDBM, y es esencialmente una matriz asociativa formada por matrices de cadenas text_t indizadas por números enteros.
invbrowserclass.h Heredado de browserclass, este objeto presta apoyo para la consulta de listas que no se presentarán en pantalla (invisibles).
nullproto.h Heredada de recptproto, este clase realiza el protocolo nulo a través de las llamadas de funciones del recepcionista al servidor de colección.
pageaction.h Acción heredada que, en combinación con el archivo de macros indicado en p=page, genera una página Web.
pagedbrowserclass.h Heredado de browserclass, este objeto presta apoyo para el mecanismo “ir a la página”, como vimos por ejemplo en la colección Gutenberg.
pingaction.h Acción heredada que comprueba si una colección particular responde.
queryaction.h Acción heredada que toma la búsqueda formulada, las configuraciones y las preferencias, efectúa la búsqueda y genera como resultado el subconjunto de documentos correspondientes o=num empezando en la posición r=num.
querytools.h Función de apoyo para las búsquedas.
receptionist.h Objeto de alto nivel del recepcionista. Mantiene un registro de las informaciones de argumentos CGI, las instancias de cada acción heredada, las instancias de cada objeto de consulta heredado, el objeto central de lenguaje de macros displayclass, así como todos los convertidores posibles.
recptconfig.h Función de apoyo para la lectura de los principales archivos de configuración y de sitio.
recptproto.h Clase de base para el protocolo.
statusaction.h Acción heredada que genera, conjuntamente con status.dm, las diversas páginas de administración.
tipaction.h Acción heredada que genera, conjuntamente con tip.dm, una página Web que contiene una sugerencia elegida de forma aleatoria a partir de una lista de sugerencias que se encuentra en tip.dm.
userdb.h Estructura de datos y función de apoyo para mantener una base de datos GDBM de usuarios: su contraseña, sus grupos, etc.
usersaction.h Una acción de administración heredada de la clase de base que permite añadir y suprimir usuarios, así como modificar los grupos a los que pertenecen.
vlistbrowserclass.h Heredado de browserclass, este objeto presta apoyo para la consulta de las listas verticales, que constituyen la base de los clasificadores. Por ejemplo, los elementos secundarios del nodo de títulos que empiezan con la letra N forman una Vlist.
z3950cfg.h Apoyo de estructura de datos para el protocolo Z39.50. Utilizado por z3950proto.cpp, que define la clase de protocolo principal (heredada de la clase de base recptproto) y el analizador del archivo de configuración zparse.y (escrito en YACC).
z3950proto.h Heredado de recptproto, esta clase implementa el protocolo Z39.50 de tal modo que el recepcionista de Greenstone pueda acceder a los sitios de bibliotecas remotas que funcionan con servidores Z39.50.
z3950server.h Apoyo complementario para el protocolo Z39.50.

Inicialización

En Greenstone, la inicialización es una operación compleja que trata archivos de configuración y asigna valores por defecto a los campos de datos. Además de las funciones de herencia y de creación, los objetos centrales definen las funciones init() y configure() para contribuir a normalizar la tarea. Aun así, el orden de ejecución puede ser difícil de seguir. En esta sección se explica lo que sucede.

Greenstone utiliza varios archivos de configuración con diferentes fines, pero todos respetan la misma sintaxis. A menos que una línea empiece por el símbolo “#” o sólo contenga espacios en blanco, la primera palabra define un término clave y las demás representan una configuración particular de dicho término clave.

Las líneas de los archivos de configuración se transmiten de una en una a la función configure() y contienen dos argumentos: el término clave y una matriz de las palabras restantes. Basándose en el término clave, una versión particular de configure() determina si la información es de interés, y si es así la guarda. Por ejemplo, collectserver (que corresponde al objeto Colección de la Figura <imgref figure_greenstone_runtime_system>) trata las instrucciones de formato del archivo de configuración de una colección. Cuando la función configure() recibe el término clave format, se activa una instrucción if que guarda en el objeto una copia del segundo argumento de la función.

Tras tratar el término clave y antes de que concluya la función, algunas versiones de configure() transmiten los datos a las funciones configure() de otros objetos. El objeto Recepcionista activa la función configure() de los objetos Acciones, Protocolos y Consulta. El objeto Protocolo nulo activa la función configure() de cada objeto Colección; el objeto Colección activa los objetos Filtro y Fuente.

En C++, los campos de datos se inicializan normalmente mediante la función de creación del objeto. Sin embargo, en Greenstone algunas inicializaciones dependen de los valores leídos en los archivos de configuración, por ello es preciso proceder a una segunda tanda de inicializaciones. Esta es la finalidad de las funciones miembro init(), y en algunos casos requiere posteriores llamadas de la función configure().

<imgcaption figure_initialising_greenstone_using_the_null_protocol|%!– id:1136 –%Inicialización de Greenstone utilizando el protocolo nulo ></imgcaption>

============
Main program
============
Statically construct Receptionist
Statically construct NullProtocol
Establish the value for ’gsdlhome’ by reading gsdlsite.cfg
Foreach directory in GSDLHOME/collect that isn’t "modelcol":
  Add directory name (now treated as collection name) to NullProtocol:
    Dynamically construct Collection
    Dynamically construct Gdbm class
    Dynamically construct the Null Filter
    Dynamically construct the Browse Filter
    Dynamically construct MgSearch
    Dynamically construct the QueryFilter
    Dynamically construct the MgGdbmSource
    Configure Collection with ’collection’
      Passing ’collection’ value on to Filters and Sources:
Configure Receptionist with ’collectinfo’:
      Passing ’collectinfo’ value on to Actions, Protocols, and Browsers:
Add NullProtocol to Receptionist
Add in UTF-8 converter
Add in GB converter
Add in Arabic converter
Foreach Action:
  Statically construct Action
  Add Action to Receptionist
Foreach Browsers:
  Statically construct Browser
  Add Browser to Receptionist
Call function cgiwrapper:
  =================
  Configure objects
  =================
  Configure Receptionist with ’collection’
    Passing ’collection’ value on to Actions, Protocols, and Browsers:
    NullProtocol not interested in ’collection’
  Configure Receptionist with ’httpimg’
    Passing ’httpimg’ value on to Actions, Protocols, and Browsers:
    NullProtocol passing ’httpimg’ on to Collection
    Passing ’httpimg’ value on to Filters and Sources:
  Configure Receptionist with ’gwcgi’
    Passing ’gwcgi’ value on to Actions, Protocols, and Browsers:
    NullProtocol passing ’gwcgi’ on to Collection
    Passing ’gwcgi’ value on to Filters and Sources:
  Reading in site configuration file gsdlsite.cfg
    Configure Recptionist with ’gsdlhome’
      Passing ’gsdlhome’ value on to Actions, Protocols, and Browsers:
      NullProtocol passing ’gsdlhome’ on to Collection
        Passing ’gsdlhome’ value on to Filters and Sources:
    Configure Recptionist with ...
    ... and so on for all entries in gsdlsite.cfg 
  Reading in main configuration file main.cfg
    Configure Recptionist with ...
    ... and so on for all entries in main.cfg
  ====================
  Initialising objects
  ====================
  Initialise the Receptionist
    Configure Receptionist with ’collectdir’
      Passing ’collectdir’ value on to Actions, Protocols, and Browsers:
      NullProtocol not interested in ’collectdir’
    Read in Macro files
    Foreach Actions
      Initialise Action
    Foreach Protocol
      Initialise Protocol
      When Protocol==NullProtocol:
        Foreach Collection
          Reading Collection’s build.cfg
          Reading Collection’s collect.cfg
            Configure Collection with ’creator’
              Passing ’creator’ value on to Filters and Sources:
            Configure Collection with ’maintainer’
              Passing ’maintainer’ value on to Filters and Sources:
            ... and so on for all entries in collect.cfg
    Foreach Browsers
      Initialise Browser
  =============
  Generate page
  =============
  Parse CGI arguments
  Execute designated Action to produce page
End.

En la Figura <imgref figure_initialising_greenstone_using_the_null_protocol> se presentan los mensajes de diagnóstico generados por una versión de Greenstone configurada para resaltar el proceso de inicialización. El programa arranca con la función main() del archivo recpt/librarymain.cpp. Crea un objeto Recepcionista y un objeto Protocolo nulo, luego recorre el archivo gsdlsite.cfg (ubicado en el mismo directorio que el ejecutable library) en  busca de gsdlhome y guarda su valor en una variable. Para cada colección en línea –lista establecida leyendo los directorios de GSDLHOME/collect – el programa crea un objeto de colección mediante el objeto Protocolo nulo, que contiene objetos Filtro, Búsqueda y Fuente, así como algunas llamadas cableadas a configure().

A continuación, la función main() agrega el objeto Protocolo nulo al recepcionista, que mantiene una matriz de clase de base de protocolos en un campo de datos protegidos, y luego activa varios convertidores. La función main() crea todos los objetos Acción y Consulta que se utilizan en el ejecutable y los incorpora al recepcionista. La función concluye al activar la función cgiwrapper() ubicada en cgiwrapper.cpp, que efectúa a su vez un número importante de inicializaciones de objetos.

La función cgiwrapper() comprende tres partes: configuración, inicialización y generación de página. En primer lugar, se efectúan algunas llamadas cableadas a la función configure(), luego se lee el archivo gsdlsite.cfg y se aplica configure a cada línea. Lo mismo ocurre con el archivo etc/main.cfg.

La segunda fase de cgiwrapper() activa init(). El objeto Recepcionista sólo hace una llamada a su función init(), pero esta acción invoca las funciones init() de los diferentes objetos que contiene. Primero una llamada cableada a configure() para instalar collectdir, y luego se leen los archivos de macros. Se activa la función init() de cada acción. Lo mismo ocurre con cada protocolo almacenado en el recepcionista, pero en el sistema que se describe aquí sólo se almacena el protocolo nulo. La activación de la función init() de este objeto suscita otras configuraciones: en cada colección del protocolo nulo se leen y se tratan los archivos específicos de la colección build.cfg y collect.cfg, y cada línea activa la función configure().

La fase final de cgiwrapper() consiste en analizar los argumentos CGI y luego activar la acción adecuada. Ambas acciones se efectúan con la asistencia del objeto Recepcionista.

Los códigos de configuración, inicialización y generación de páginas están separados porque Greenstone está concebido para funcionar como servidor (con Fast-CGI, el protocolo CORBA, o la versión Biblioteca Local de Windows). En ese modo de funcionamiento, el código de configuración y de inicialización sólo se ejecuta una vez, y luego el programa permanece en memoria y genera numerosas páginas Web en respuesta a las consultas de los usuarios sin necesidad de volverse a inicializar.

1)
El valor de gsdlhome procede del archivo gsdlsite.cfg ubicado en el mismo directorio que el ejecutable CGI library, mientras que GSDLHOME se activa ejecutando el guión setup que da acceso a un archivo diferente; así pues, es posible técnicamente que los dos valores sean diferentes, pero no es deseable. El texto que figura más arriba está escrito partiendo de la hipótesis de que ambos valores son iguales.
legacy/manuals/es/develop/the_greenstone_runtime_system.txt · Last modified: 2023/03/13 01:46 by 127.0.0.1