Eclipse y HSQLDB: Incorporación de un servidor de base de datos relacional en Eclipse, Parte 1

Cómo escribir un plug-in que integre el servidor de base de datos de HSQLDB en la estación de Trabajo de Eclipse

Este artículo muestra cómo desarrollar un plug-in que intercale el servidor de base de datos relacional de Java puro de HSQLDB en la Estación de Trabajo de Eclipse. Aunque no es tan poderoso como DB2 ni tan popular como MySQL, HSQLDB (la base de datos de SQL hipersónica) puede satisfacer las necesidades de una amplia gama de aplicaciones de Java, debido a su extensibilidad y bajos requisitos de memoria/procesador.

Fernando Lozano, Consultor independiente

Fernando Lozano ha sido desde hace mucho tiempo fanático del código abierto y desarrollador de Java, autor del libro Java and GNU/Linux (disponible sólo en portugués). Entre otras actividades, vender servicios a organizaciones que desarrollan aplicaciones de J2EE utilizando Eclipse y otras herramientas de código abierto, ayuda a mantener la traducción en portugués del sitio web de GNU Project y es parte del consejo de Linux Professional Institute Brazil. Es posible contactar a Fernando escribiendo a fernando at lozano.eti.br.



17-12-2012

La base de datos de SQL hipersónica, cuyo nombre oficial después fue cambiado por HSQLDB, es un servidor de base de datos relacional incorporado de Java puro. Es posible lo utilizar en modo autónomo (utilizando acceso a archivos directo) o en modo cliente/servidor, aceptando muchos usuarios concurrentes. Aunque no es tan poderoso como DB2 ni tan popular como MySQL, HSQLDB puede satisfacer las necesidades de una amplia gama de aplicaciones de Java, debido a su extensibilidad y bajos requisitos de memoria/procesador.

HSQLDB es una base de datos de desarrollo de Java conveniente debido a que presenta un subconjunto enriquecido de lenguaje de consulta estructurado (SQL) y porque los programadores no necesitarán instalar un procesador, memoria o servidor de base de datos que requiera de espacio en disco en su estación de trabajo de desarrollo. Es una herramienta ideal para la integración con el IDE de Eclipse, proporcionando herramientas útiles para desarrolladores nuevos y expertos.

Este artículo y los siguientes en esta serie le mostrarán cómo compilar un conjunto de plug-ins de Eclipse que lleven HSQLDB a la Estación de Trabajo de Eclipse. Verá un ejemplo del mundo real sobre cómo desarrollar un plug-in como este, considerando problemas de API y de interfaz de usuario (UI) y también cómo evaluar rutas alternativas para llevar la funcionalidad deseada a un usuario. Este artículo asume que está utilizando la distribución del SDK de Eclipse y no el Binario de Tiempo de Ejecución de la Plataforma más JDT. Este último sería apropiado si la meta fuera sólo desarrollar una aplicación regular de Java.

En esta serie, crearemos y expandiremos el conjunto de plug-ins utilizando tres etapas, de acuerdo con lo descrito en los "Niveles de Integración" (vea Resources más adelante en este artículo para obtener un enlace):

  1. Iniciar herramientas existentes desde Eclipse, proporcionando un acceso fácil a herramientas previamente existentes deseadas desde los menú de la Estación de Trabajo
  2. Explorar cómo pueden ser utilizados otros dispositivos de Eclipse para añadir valor al conjunto previamente existente de herramientas, mejorando la productividad del desarrollador de Java
  3. Volver a grabar las herramientas utilizando SWT para una integración perfecta en la Estación de Trabajo de Eclipse

Conozca HSQLDB

Es posible descargar HSQLDB, incluyendo sus fuentes y documentación, desde SourceForge (hsqldb.sourceforge.net; vea el enlace en Resources). Esto no debe confundirse con el proyecto de SourceForge original, hsql.sourceforge.net, el cual ha sido congelado.

La distribución binaria es un archivo ZIP estándar y todo lo que necesita hacer es descomprimirlo en algún lugar de su unidad de disco duro. Todos los componentes de HSQLDB -- el motor de la base de datos, los procesos del servidor, el controlador de JDBC, la documentación y un puñado de utilidades -- son proporcionados en un solo paquete de JAR, instalado en lib/hsqldb.jar y pesan alrededor de 260 KB. El motor de la base de datos necesita sólo 170 KB de RAM para ejecutarse, haciéndolo adecuado para PDAs como Zaurus de Sharp, y la descarga completa, incluyendo las fuentes y la documentación, es lo suficientemente pequeña para caber en un disquete estándar de 1.44 MB.

Es posible iniciar el servidor de la base de datos y las utilidades desde el indicador de comandos al invocar clases de conveniencia como org.hsqldb.Server y org.hsqldb.util.DatabaseManager, cada una de las cuales acepta un pequeño conjunto de opciones de línea de comandos como "-url" (para conexiones remotas), "-database" (para acceso a archivos directo) y "-user". También se acepta la opción "-?" para proporcionar ayuda sobre sintaxis de línea de comandos válida.

La clave de la simplicidad de HSQLDB es la serialización de la ejecución de sentencias SQL. Es decir, aunque muchos usuarios concurrentes pueden estar conectados a la base de datos (cuando se ejecuta en el modo de servidor), todas las sentencias SQL están colocadas en una cola y son ejecutadas una a la vez. Por lo tanto, no hay necesidad de implementar algoritmos complicados de bloqueo y sincronización. A pesar de eso, HSQLB implementa semántica de ACID (Atomicidad, Consistencia, Aislamiento y Durabilidad). En otras palabras, es una base de datos transaccional, pero sólo al nivel de lectura no confirmada , sin aislamiento de transacciones. HSQLDB realmente fue creado para aplicaciones incorporadas, no para el centro de datos corporativo.

Si desea desencadenantes, funciones agregadas, uniones exteriores, vistas y otros dispositivos de SQL, puede encontrarlos ahí (algo que no obtendrá de la mayoría de las bases de datos relacionales ligeras). Es posible implementar procedimientos almacenados al añadir sus clases de Java a la ruta de clase de HSQLDB. Después usted emite una sentencia CREATE FUNCTION y ya ha terminado. De hecho, muchas funciones SQL estándar como SQRT y ABS son implementadas como correlaciones con clases de Java estándar como java.lang.Math.

Modelos de operación de HSQLDB

El motor de HSQLDB puede ser ejecutado en muchos modos para ajustarse a distintos escenarios de aplicación:

Modo en memoria
Todas las tablas e índices de base de datos son mantenidos en la memoria y nunca salvados en el disco. Antes de que pregunte por qué alguien querría una base de datos que esté perdida en la finalización de aplicaciones, piense en tener una memoria caché local para datos de base de datos que es posible consultar, ordenar, agrupar y actualizar utilizando sentencias SQL estándar.

Modo autónomo
La aplicación crea una conexión de base de datos utilizando JDBC y el motor de HSQLDB se ejecuta dentro de la aplicación, accediendo a los archivos de la base de datos directamente. No pueden haber usuarios concurrentes (la aplicación tiene acceso exclusivo a los archivos de la base de datos), pero no hay hebras adicionales ni sobrecarga de conexión de TCP. El modo autónomo es el preferido para muchas aplicaciones intercaladas.

Modo de servidor
Esta es la configuración estándar de la base de datos de cliente/servidor similar a otras bases de datos relacionales, permitiendo las conexiones concurrentes utilizando sockets de TCP. La mayoría de los desarrolladores querrán este modo, ya que permite que cualquier cliente de JDBC se conecte y consulte/actualice tablas mientras la aplicación principal sigue en ejecución.

Modo de servidor web
HSQLDB puede actuar como un servidor web, aceptando consultas de SQL mediante HTTP, o puede ejecutarse como un servlet dentro de cualquier contenedor web estándar, pasando a través de firewalls o instalado en un servicio de alojamiento web sin involucrar al equipo de soporte del proveedor (y las costosas opciones de alojamiento de bases de datos). Como HTTP no tiene estado, no hay transacciones en este modo.

Estructura de archivos de base de datos de HSQLDB

HSQLDB mantiene todos los datos de tabla e índice en la memoria, salvando todas las sentencias SQL emitidas en un archivo llamado database.script, el cual también actúa como el registro de transacción. Cuando el motor es inicializado, este archivo es leído y todas las sentencias SQL son procesadas, recreando así toda la base de datos. Durante la conclusión, el motor de HSQLDB generará un nuevo archivo database.script con el conjunto mínimo de sentencias para una rápida inicialización de la base de datos.

Además de las tablas de memoria predeterminadas, HSQLDB también soporta tablas "en caché" y "de texto". Los datos para todas las tablas en caché son mantenidos en un archivo llamado database.data, mientras que los datos de tabla de texto son mantenidos en cualquier archivo de texto delimitado (como archivos CS) llamado por la sentencia SQL no estándar set table source . Aunque las tablas en caché proporcionan soporte para conjuntos de datos más grandes que el RAM disponible, las tablas de texto son una forma conveniente de importar y exportar datos.

Además de los archivos database.script y database.data, cualquier base de datos de HSQLDB puede incluir un archivo database.properties, en el cual el administrador puede establecer muchos parámetros que afectan la compatibilidad de ANSI SQL. Todos los archivos de base de datos (excepto los archivos de datos de tabla de texto) deben mantenerse en el mismo directorio.

No hay una forma específica para crear bases de datos de HSQLDB. Si le pide al motor que abra un archivo de base de datos no existente (utilizando la opción -database del modo de servidor o un URL de JDBC del modo autónomo), el archivo y el directorio que lo contiene serán creados. Por lo tanto, si está seguro de que había datos en esa base de datos vacía, verifique si hay errores de escritura.

¡Ahora comencemos a desarrollar el plug-in!


Crear el conjunto de plug-ins de Eclipse de HSQLDB

Poner una aplicación existente dentro de una herramienta poderosa como Eclipse no es una tarea trivial. Afortunadamente, tanto HSQLDB como Eclipse facilitan la tarea, ya que HSQLDB es intercalable en otras aplicaciones y Eclipse proporciona una infraestructura de plug-ins limpia y fácil de entender y un entorno de desarrollo robusto para crear nuevos plug-ins, el PDE. Aún si no tiene experiencia previa con el desarrollo de plug-ins de Eclipse, el PDE hace que la tarea sea bastante fácil. Vea los artículos que cubren las bases de Eclipse en Resources .

Estas instrucciones asumen que está utilizando la distribución del SDK de Eclipse y no el Binario de Tiempo de Ejecución de la Plataforma más JDT. Este último sería apropiado si su meta fuera sólo desarrollar una aplicación regular de Java. Es posible utilizar su sistema operativo preferido, ya que sólo usaremos código de Java y nada de código nativo.

Comenzaremos con el esfuerzo mínimo para crear un conjunto útil de plug-ins y escribir la cantidad más pequeña de código. Más adelante, en las siguientes partes de esta serie, veremos cómo pueden ser aprovechados los dispositivos de Eclipse para proporcionar valor añadido a HSQLDB.

En este artículo, nos enfocaremos en la siguiente funcionalidad para nuestro código:

  1. Inicie el motor de HSQLDB en modo de servidor, de forma que la aplicación de usuario y una consola de SQL (como la utilidad DatabaseManager del propio HSQLDB) puedan ejecutar sentencias SQL al mismo tiempo.
  2. Inicie la base de datos de HSQLDB en forma limpia.
  3. Invoque la utilidad DatabaseManager de forma que los desarrolladores puedan ingresar sentencias SQL en forma interactiva desde la Estación de Trabajo.
  4. Ejecute los archivos de script utilizando la utilidad ScriptTool de HSQLDB. Con el paso de los años, he mantenido muchos archivos *.sql en mis carpetas de proyecto, para crear tablas de base de datos e insertar datos de prueba, y desde hace mucho tiempo he deseado contar con una forma fácil de ejecutarlas.
  5. Configure las propiedades de conexión de HSQLDB, como el puerto TCP y la contraseña de administrador.

¿Cómo se harán estas funciones disponibles para la Estación de Trabajo? La forma más fácil para realizar las primeras tres es proporcionar un actionSet, añadido a un nuevo menú de nivel superior y también accesible desde su propia barra de herramientas. La acción para ejecutar archivos de script de SQL debe atarse sólo a archivos con una extensión "*.sql", así que esto será un objectContribution, añadido por la Estación de Trabajo a los menús desplegables en cualquier vista que muestre estos archivos. Finalmente, los parámetros de conexión se ajustan bien en una página de preferencias de plug-in, accesible desde el menú Workbench Window.

La Figura 1 muestra el nuevo menú y barra de herramientas, mientras que la Figura 2 muestra la nueva entrada en el menú emergente para la vista Navigator y la Figura 3 muestra la página de propiedades, de forma que es posible obtener una vista previa de cómo se verá el primer release de nuestro plug-in.

Figura 1. Menú de HSQLDB y la barra de herramientas asociada
HSQLDB menu and associated toolbar
Figura 2. Elemento de menú emergente añadido a archivos *.sql
Popup menu item added to *.sql files
Figura 3. Propiedades de conexión de HSQLDB
HSQLDB connection properties

Convirtiendo HSQLDB en un plug-in de Eclipse

La primera etapa en la compilación de nuestro conjunto de plug-ins es empaquetar a HSQLDB mismo como un plug-in de Eclipse. Este plug-in contendrá sólo hsqldb.jar y el necesario archivo plugin.xml requerido por la Estación de Trabajo. Si ha explorado el directorio de plug-ins de Eclipse estándar, ya ha descubierto que JUnit, Xerces, Tomcat y otros populares paquetes de Java están aislados en sus propios plug-ins, sin cambios, y que todos esos específicos de Eclipse están encapsulados en otros plug-ins. Esta compartimentación hace que sea fácil actualizar estas herramientas de terceros, las cuales no necesariamente requieren cambios para Eclipse mismo. Otro beneficio es la facilidad de compartir estas bibliotecas comunes con muchos plug-ins.

Abra su instalación del SDK de Eclipse y cree un nuevo proyecto de plug-in; llámelo hsqldb.core. (Sé que el nombre recomendado sería org.hsqldb.core, pero no pretendo tomar el espacio de nombres de HSQLDB. Quizá a los desarrolladores de HSQLDB que estén leyendo esto les gustará esta idea y la recomendarán como el plug-in "oficial" de integración de Eclipse; en ese caso, el nombre probablemente cambiaría.) Asegúrese de seleccionar la opción "Empty Plugin" en lugar de cualquier plantilla de plug-in; de otra manera, obtendrá una clase de plug-in de nivel superior inútil, la cual puede ser eliminada con seguridad si fue impaciente y ya la ha creado. Copie hsqldb.jar de su instalación de HSQLDB en el directorio del proyecto y añádalo al Tiempo de Ejecución del proyecto. Es posible hacer esto al utilizar PDE Plugin Manifest Editor o simplemente al copiar el contenido del Listado 1.

Listado 1. Archivo de manifiesto plugin.xml para el plug-in hsqldb.core
<?xml version="1.0" encoding="UTF-8"?>
<plugin
   id="hsqldb.core"
   name="Hsqldb Core Plug-in"
   version="0.0.1"
   provider-name="Fernando Lozano (www.lozano.eti.br)">

   <runtime>
      <library name="hsqldb.jar">
         <export name="*"/>
      </library>
   </runtime>

</plugin>

Añadir extensiones de Estación de Trabajo

A continuación, cree un segundo proyecto de plug-in llamado hsqldb.ui. Esto contendrá todas las extensiones de Eclipse para la primera revisión del conjunto de plug-ins: un conjunto de acciones que contiene tres acciones, una contribución de objeto asociada con archivos *.sql y una página de propiedades. Nombre su clase principal (clase Plugin ) PluginUi, aceptando el nombre de paquete predeterminado hsqldb.ui.

Abra el archivo plugin.xml utilizando Plugin Manifest Editor y seleccione la pestaña Extensions. Renombre el menú contribuido a HSQLDB y cambie la acción de muestra de forma que presente la etiqueta "Runs HSQLDB Database Manager". Añada otras dos acciones al mismo actionSet con las etiquetas "Stops HSQLDB database server" y "Starts HSQLDB database server", suministrando cada una con un id de acción exclusiva y una clase de implementación. Tenga en cuenta que las acciones serán mostradas en el menú y la barra de herramientas en el orden de creación inverso (es decir, el orden de aparición inverso en el archivo de manifiesto del plug-in).

Haga clic en el botón Add para añadir dos nuevas extensiones utilizando las plantillas Extension, un menú emergente y una página de propiedades. El menú emergente debe estar asociado con el patrón del archivo *.sql, pero los campos de la página de propiedades serán establecidos programáticamente.

La Figura 4 muestra cómo el editor Plugin Manifest debe aparecer al final, mostrando todas las extensiones de plug-in; la Figura 5 muestra las propiedades para la contribución del objeto (note el filtro para los archivos *.sql) y la Figura 6 muestra las propiedades para la acción "Run SQL Script" para el menú emergente de recursos de archivo. Los iconos están en el código de origen de este artículo (vea Resources), ¡pero estoy seguro de que conoce un experto en gráficos que puede dibujarlos mejor!

Figura 4. Acciones de HSQLDB en el editor de manifiesto
HSQLDB actions on the manifest editor
Figura 5. Contribución de objeto de HSQLDB en el editor de manifiesto
HSQLDB object contribution on the manifest editor
Figura 6. Acción Run SQL Script en el editor de manifiesto
Run SQL Script action on the manifest editor

Antes de que el código pueda ser añadido a nuestras acciones, necesitamos informar a este plug-in de IU sobre el plug-in principal correspondiente, de otra forma no tendrá acceso a clases de HSQLDB. Cámbiese a la página "Dependencies" en Plugin Manifest Editor y añada una dependencia de plug-in, como se muestra en la Figura 7. Algunas dependencias, como "eclipse.ui", fueron configuradas automáticamente por el PDE, mientras que otras como "org.eclipse.debug.core" serán añadidas cuando las acciones sean codificadas. Si prefiere editar el código XML directamente, el Listado 2 muestra el archivo plugin.xml completo para el plug-in hsqldb.ui.

Para completar la configuración del plug-in, añada una nueva Clase al paquete hsqldb.ui y llámela HsqldbUtil. Esta clase contendrá todo el código que se encarga directamente de HSQLDB, manteniendo simple el código de extensiones contribuidas.

Figura 7. Dependencias del plug-in hsqldb.ui
hsqldb.ui plug-in main proprieties
Listado 2. Archivo de manifiesto de plugin.xml para el plug-in hsqldb.ui
<?xml version="1.0" encoding="UTF-8"?>
<plugin
   id="hsqldb.ui"
   name="Hsqldb Ui Plug-in"
   version="0.0.1"
   provider-name="Fernando Lozano (www.lozano.eti.br)"
   class="hsqldb.ui.PluginUi">

   <runtime>
      <library name="ui.jar"/>
   </runtime>
   <requires>
      <import plugin="org.eclipse.core.resources"/>
      <import plugin="org.eclipse.ui"/>
      <import plugin="hsqldb.core"/>
      <import plugin="org.eclipse.debug.core"/>
      <import plugin="org.eclipse.jdt.launching"/>
      <import plugin="org.eclipse.debug.ui"/>
   </requires>

   <extension
         point="org.eclipse.ui.actionSets">
      <actionSet
            label="Hsqldb"
            visible="true"
            id="hsqldb.ui.actionSet">
         <menu
               label="Hsql&db"
               id="hsqldbMenu">
            <separator
                  name="dbServerGroup">
            </separator>
         </menu>
         <action
               label="Run Hsql &Database Manager"
               icon="icons/dbman.gif"
               tooltip="Runs the Hsql database manager"
               class="hsqldb.ui.actions.HsqldbDatabaseManagerAction"
               menubarPath="hsqldbMenu/dbServerGroup"
               toolbarPath="dbServerGroup"
               id="hsqldb.ui.actions.HsqldbDatabaseManagerAction">
            <enablement>
               <pluginState
                     value="activated"
                     id="hsqldb.ui">
               </pluginState>
            </enablement>
         </action>
         <action
               label="S&top Hsqldb"
               icon="icons/stop.gif"
               tooltip="Stops the Hsql database server"
               class="hsqldb.ui.actions.HsqldbStopAction"
               menubarPath="hsqldbMenu/dbServerGroup"
               toolbarPath="dbServerGroup"
               id="hsqldb.ui.actions.HsqldbStopAction">
            <enablement>
               <pluginState
                     value="activated"
                     id="hsqldb.ui">
               </pluginState>
            </enablement>
         </action>
         <action
               label="&Start Hsqldb"
               icon="icons/start.gif"
               tooltip="Starts the Hsql database server"
               class="hsqldb.ui.actions.HsqldbStartAction"
               menubarPath="hsqldbMenu/dbServerGroup"
               toolbarPath="dbServerGroup"
               id="hsqldb.ui.actions.HsqldbStartAction">
            <enablement>
               <pluginState
                     value="installed"
                     id="hsqldb.ui">
               </pluginState>
            </enablement>
         </action>
      </actionSet>
   </extension>
   <extension
         point="org.eclipse.ui.perspectiveExtensions">
      <perspectiveExtension
            targetID="org.eclipse.ui.resourcePerspective">
         <actionSet
               id="hsqldb.ui.actionSet">
         </actionSet>
      </perspectiveExtension>
   </extension>
   <extension
         point="org.eclipse.ui.popupMenus">
      <objectContribution
            objectClass="org.eclipse.core.resources.IFile"
            nameFilter="*.sql"
            id="hsqldb.ui.SQLScriptFiles">
         <action
               label="Run SQL Script"
               class="hsqldb.ui.popup.actions.HsqldbRunScript"
               menubarPath="additions"
               enablesFor="1"
               id="hsqldb.ui.HsqldbRunScript">
            <enablement>
               <pluginState
                     value="activated"
                     id="hsqldb.ui">
               </pluginState>
            </enablement>
         </action>
      </objectContribution>
   </extension>
   <extension
         id="hsqldb.ui.preferences"
         point="org.eclipse.ui.preferencePages">
      <page
            name="HSQLDB Server"
            class="hsqldb.ui.preferences.HSQLDBPreferencePage"
            id="hsqldb.ui.preferences.HSQLDBPreferencePage">
      </page>
   </extension>
</plugin>

Iniciando HSQLDB

Es fácil iniciar el motor de HSQLDB en modo de servidor utilizando la clase org.hsqldb.Server. Como los argumentos de línea de comandos, obtiene el nombre de base de datos (ruta + nombre base para archivos de base de datos), el puerto TCP para escuchar solicitudes de conexión y un distintivo que le dice si debe llamar a System.exit() en la conclusión. La siguiente línea de comandos sería típica de una ejecución de HSQLDB:

java -cp /opt/hsqldb/hsqldb.jar org.hsqldb.Server -database /tmp/bd -port 9001 -system_exit=true

La línea anterior crea los archivos de base de datos /tmp/db.script, /tmp/db.properties y /tmp/db.data.

Podemos simplemente utilizar el método principal de la clase Server y pasar los argumentos como un array de Series. Pero tenemos que hacer esto dentro de una nueva hebra; de otra manera, bloquearemos toda la Estación de Trabajo. La clase de plug-in, la cual es un singleton, mantiene una referencia a esta hebra, de forma que puede verificar si hay un servidor que comenzó a ejecutarse antes de intentar conectarse a él y también verificar si se está ejecutando realmente, ya que cualquier cliente puede conectarse y utilizar la sentencia SHUTDOWN , finalizando el servidor.

El código en el Listado 3 muestra el método run para hsqldb.ui.actions.HsqldbStartAction y el Listado 4 muestra el código para startHsqldb desde hsqldb.ui.HsqldbUtil, el cual en realidad inicia el servidor. Más adelante, discutiremos las técnicas para gestionar la retroalimentación del usuario.

La parte más interesante de este código es cómo encontramos una ubicación para mantener los archivos de la base de datos. Un proyecto llamado .hsqldb es creado si no existe ya, y dentro de él el motor buscará database.script y otros archivos de base de datos.

Eclipse proporciona todos los plug-ins en un directorio estándar donde cualquier archivo de configuración puede ser salvado. Dicho directorio puede ser obtenido al llamar plugin.getStateLocation, pero no siento que los archivos de base de datos sean realmente archivos de configuración de plug-in. Se ven más como archivos de datos de usuario y, como tales, deben estar dentro de un proyecto en el espacio de trabajo del desarrollador.

Listado 3. Acción para iniciar HSQLDB en modo de servidor, desde hsqldb.ui.actions.HsqldbStartAction
    public void run(IAction action) {
        // check a database was really started by the plug-in
        PluginUi plugin = PluginUi.getDefault();
        if (plugin.getHsqldbServer() != null) {
            ((ApplicationWindow)window).setStatus(
                "HSQLDB Server already running.");
        }
        else {
            Cursor waitCursor = new Cursor(window.getShell().getDisplay(),
                SWT.CURSOR_WAIT);
            window.getShell().setCursor(waitCursor);
            try {
                HsqldbUtil.startHsqldb();
                ((ApplicationWindow)window).setStatus("HSQLDB Server started.");
            }
            catch (CoreException e) {
                MessageDialog.openError(window.getShell(),
                    "Hsqldb Plugin",
                    "Could not create HSQLDB database project.");
                e.printStackTrace(System.err);
            }
            finally {
                window.getShell().setCursor(null);
                waitCursor.dispose();
            }
        }
    }
Listado 4. Código que realmente inicia HSQLDB en modo de servidor, desde hsqldb.ui.HsqldbUtil
    public static void startHsqldb() throws CoreException {
        PluginUi plugin = PluginUi.getDefault();
        // finds project local path for database files
        IWorkspaceRoot root = PluginUi.getWorkspace().getRoot();
        IProject hsqldbProject = root.getProject(".hsqldb");
        if (!hsqldbProject.exists()) {
            hsqldbProject.create(null);
        }
        hsqldbProject.open(null);
        IPath dbPath = hsqldbProject.getLocation();
        final String database = dbPath.toString() + "/database";
        // starts a new thread to run the database server
        final HsqldbParams params = getConnectionParams();
        Thread server = new Thread() {
            public void run() {
                String[] args = { "-database", database,
                    "-port", String.valueOf(params.port),
                    "-no_system_exit", "true" };
                Server.main(args);
            }
        };
        plugin.setHsqldbServer(server);
        server.start();
    }

Deteniendo HSQLDB

Para detener el servidor de HSQLDB, lo único que se necesita es un comando SHUTDOWN como una sentencia SQL. El método stopHsqldb desde hsqldb.ui.HsqldbUtil, mostrado en el Listado 5, hace precisamente eso. El código para la acción correspondiente será el mismo que el descrito para iniciar el servidor, así que no lo listaremos aquí. ExcepcionesClassNotFoundException (desde Class.forName) y SQLException son lanzadas de forma que el código de acción pueda proporcionar una retroalimentación adecuada para el usuario.

Listado 5. Código para detener el servidor HSQLDB
    public static void stopHsqldb() throws ClassNotFoundException,
                SQLException {
        PluginUi plugin = PluginUi.getDefault();
        HsqldbParams params = getConnectionParams();
        // submits the SHUTDOWN statement
        Class.forName("org.hsqldb.jdbcDriver");
        String url = "jdbc:hsqldb:hsql://127.0.0.1:" + params.port;
        Connection con = DriverManager.getConnection(url, params.user,
            params.passwd);
        String sql = "SHUTDOWN";
        Statement stmt = con.createStatement();
        stmt.executeUpdate(sql);
        stmt.close();
        // no need to close a dead connection!
        plugin.setHsqldbServer(null);
    }

Ejecutar el Gestor de Base de Datos de HSQL

Ejecutar la utilidad de Gestor de Base de Datos de HSQLDB es un poco más complicado que ejecutar el servidor mismo. Aunque el servidor fue creado para ser intercalable en otras aplicaciones, la utilidad fue creada para ser ejecutada como una aplicación autónoma o como un applet de Java. Aunque ambos modos aceptan argumentos de línea de comandos (o parámetros de applet), no queremos la sobrecarga extra de iniciar una nueva VM de Java sólo para obtener una Ventana donde el usuario pueda escribir sentencias SQL. Llamar a la clase static void main(String[] args) directamente no funcionará como se espera, ya que invocaría System.exit() y así se finalizaría la Estación de Trabajo.

Explorando el código de origen de org.hsqldb.util.DatabaseManager , encontramos que puede ser fácilmente instanciado e inicializado con una conexión de JDBC, pero los métodos requeridos no son públicos. Así que podemos crear una clase llamada org.hsqldb.util.PatchedDatabaseManager dentro del árbol de origen de HSQLDB y utilizar el script de compilación Ant proporcionado para generar un nuevo hsqldb.jar que contenga nuestro Gestor de Base de Datos parchado. Sólo dos métodos necesitan tener su visibilidad cambiada a pública: void main() y void connect(Connection con). Utilizándolos, el Listado 6 muestra cómo el plug-in ejecuta la clase parchada.

El Gestor de Base de Datos es una aplicación de AWT (vea la Figura 8), la cual crea su propia hebra de eventos (independientemente de aquel en el SWT de Eclipse) y se finaliza al cerrar la Estación de Trabajo, la cual llama a System.exit(). No hay problema con ejecutar múltiples instancias de la utilidad, excepto por la falta de ataduras a la ventana de la Estación de Trabajo. Eso está bien para la primera revisión de nuestro plug-in de HSQLDB, pero antes de que esta serie termine tendremos que cambiarlo para que sea una aplicación de SWT alojada como una vista de Eclipse.

Figura 8. Gestor de Base de Datos de HSQLDB
HSQLDB Database Manager
Listado 6. Iniciando la utilidad parchada del Gestor de Base de Datos
    public static void runDatabaseManager() throws ClassNotFoundException,
                SQLException {
        PluginUi plugin = PluginUi.getDefault();
        HsqldbParams params = getConnectionParams();
        // creates a connection to the internal database 
        String url = "jdbc:hsqldb:hsql://127.0.0.1:" + params.port;
        Class.forName("org.hsqldb.jdbcDriver");
        Connection con = DriverManager.getConnection(url, params.user,
            params.passwd);
        if (con != null) {
            // needed to patch DatabaseManager so it could
            // be initialized and use the supplied connection 
            PatchedDatabaseManager dm = new PatchedDatabaseManager();
            dm.main();
            dm.connect(con);
        }        
    }

Ejecutando scripts de SQL

La Herramienta de Scripts de HSQLDB lee archivos de texto plano y ejecuta las sentencias SQL incluidas con un URL de JDBC proporcionada. Los lotes de sentencias SQL son separados por el comando go y los scripts también pueden utilizar el comando print para escribir mensajes desde el script.

Los desarrolladores que estén familiarizados con otros sistemas de base de datos pueden crear scripts que contengan sólo sentencias SQL delimitadas por punto y comas (;), pero esto hace que HSQLDB ejecute todos los scripts en un solo lote, retornando sólo los últimos resultados de la sentencia. Es necesario incluir el comando go entre la sentencia SQL para recibir los resultados de cada uno.

La forma más fácil de permitir al usuario explorar resultados de script es ponerlos después en una vista de consola, igual que las aplicaciones de Java y los scripts de compilación de Ant invocados desde la Estación de Trabajo. Esto requiere una configuración de Java Launch, la cual a su vez crea otra VM de Java. Como los scripts de SQL tienen poca vida, podemos considerar que la sobrecarga sea aceptable, y si piensa que el Gestor de Base de Datos también debe ser invocado en su propia VM, es posible utilizar el método runScriptTool presentado en el Listado 7 como un ejemplo.

El Listado 7 es el más largo en este primer artículo, y la mayoría él está relacionado con la configuración de una ruta de clase que contiene las clases de programa de arranque de JRE correctas (lo cual debe ser establecido específicamente) y hsqldb.jar del plug-in hsqldb.core. Vea la sección Resources al final de este artículo para obtener más información sobre la infraestructura de lanzamiento proporcionada por Eclipse y extensiones proporcionadas por el JDT.

Para los desarrolladores que están familiarizados con otros kits de herramientas de GUI, no es obvio cómo obtener la ruta para el archivo de script de SQL seleccionado. La interfaz IObjectActionDelegate , la cual es implementada por contribuciones de objeto que extienden menús emergentes de recursos, recibe en su propio método run sólo una referencia para la acción misma, igual que una acción de menú de nivel superior, que no contiene información sobre el recurso seleccionado o el control de origen. La referencia de recurso es realmente proporcionada para el método selectionChanged y tiene que ser salvada como una variable de instancia, de forma que pueda ser utilizada después -- vea el Listado 8.

Listado 7. Ejecutando la Herramienta de Scripts de HSQLDB
    public static void runScriptTool(IFile currentScript) throws CoreException {
        PluginUi plugin = PluginUi.getDefault();
        // destroys any preexisting configuration and create a new one
        ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager();
        ILaunchConfigurationType type = manager.getLaunchConfigurationType(
            IJavaLaunchConfigurationConstants.ID_JAVA_APPLICATION);
        ILaunchConfiguration[] configurations = manager.getLaunchConfigurations(
            type);
        for (int i = 0; i > configurations.length; i++) {
            ILaunchConfiguration config = configurations[i];
            if (config.getName().equals("SQL Script")) {
                config.delete();
            }
        }
        ILaunchConfigurationWorkingCopy wc = type.newInstance(null,
            "SQL Script");
        // constructs a classpath from the default JRE...
        IPath systemLibs = new Path(JavaRuntime.JRE_CONTAINER);
        IRuntimeClasspathEntry systemLibsEntry =
            JavaRuntime.newRuntimeContainerClasspathEntry(
                systemLibs, IRuntimeClasspathEntry.STANDARD_CLASSES);
        systemLibsEntry.setClasspathProperty(
            IRuntimeClasspathEntry.BOOTSTRAP_CLASSES);
        //... plus hsqldb.core plugin
        IPluginRegistry registry = Platform.getPluginRegistry();
        IPluginDescriptor hsqldbCore = registry.getPluginDescriptor(
            "hsqldb.core");
        ILibrary[] libs = hsqldbCore.getRuntimeLibraries();
        String installDir = hsqldbCore.getInstallURL().toExternalForm();
        URL hsqldbJar = null;
        try {
            hsqldbJar = Platform.asLocalURL(new URL(installDir +
                libs[0].getPath()));
        }
        catch(Exception e) {
            // ignore URL exceptions
        }
        IRuntimeClasspathEntry hsqldbEntry =
            JavaRuntime.newArchiveRuntimeClasspathEntry(new Path(
                hsqldbJar.getPath()));
        hsqldbEntry.setClasspathProperty(IRuntimeClasspathEntry.USER_CLASSES);
        // sets the launch configuration classpath
        List classpath = new ArrayList();
        classpath.add(systemLibsEntry.getMemento());
        classpath.add(hsqldbEntry.getMemento());
        wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_CLASSPATH,
            classpath);
        wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_DEFAULT_CLASSPATH,
            false);
        // current directory should be the script container
        IPath dir = currentScript.getParent().getLocation();
        wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY,
            dir.toString());
        // gets the path for the selected SQL script file
        wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME,
            "org.hsqldb.util.ScriptTool");
        // builds ScriptTool command line
        HsqldbParams params = getConnectionParams();
        String args = "-driver org.hsqldb.jdbcDriver " +
            "-url jdbc:hsqldb:hsql: " +
            "-database //127.0.0.1:" + params.port + " " +
            "-user " + params.user + " " +
            "-script " + currentScript.getName();
        if (params.passwd.length() > 0)
            args += "-password " + params.passwd + " ";
        wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS,
            args);
        // saves the new config and launches it
        ILaunchConfiguration config = wc.doSave();
        DebugUITools.launch(config, ILaunchManager.RUN_MODE);
    }
Listado 8. Cómo hacer que el Script de SQL sea ejecutado, desde hsqldb.ui.popup.actions.HsqldbRunScript
    public void selectionChanged(IAction action, ISelection selection) {
        currentScript = null;
        if (selection != null) {
            if (selection instanceof IStructuredSelection) {
                IStructuredSelection ss = (IStructuredSelection)selection;
                // as this action is enabled only for a single selection,
                // it's enough to get the first element
                Object obj = ss.getFirstElement();
                if (obj instanceof IFile) {
                    currentScript = (IFile)obj;
                }
            }
        }
    }

Propiedades de HSQLDB

Con la mayoría de la funcionalidad de nuestro plug-in en su lugar, sólo falta una forma de configurar los parámetros de conexión del servidor: el puerto TCP al que escucha, el nombre de usuario del administrador y la contraseña del usuario administrador. El puerto TCP tal vez tenga que ser cambiado, de forma que no esté en conflicto con otras aplicaciones instaladas en la máquina del desarrollador; el usuario y la contraseña pueden cambiarse con sentencias SQL desde cualquier cliente. Estos parámetros pueden ponerse en una clase de estructura de tipo C (o registro de tipo pascal) llamada HsqldbParams, la cual es mostrada en el Listado 9. También declara constantes utilizadas por el Almacén de Preferencias del Plug-in y la Página de Propiedades para captar y salvar los valores de parámetros (preferencias).

Listado 9. Estructura de preferencias para parámetros de conexión del servidor de HSQLDB
package hsqldb.ui;

public class HsqldbParams {
    // preference names for the plugin
    public static final String P_PORT = "serverPort";
    public static final String P_USER = "serverUser";
    public static final String P_PASSWD = "serverPasswd";
    
    public int port = 9001;
    public String user = "sa";
    public String passwd = "";
}

Desafortunadamente, la clase de página de preferencias generada por PDE New Extension Wizard es un poco engañosa, incluyendo un método para establecer valores de preferencia predeterminados que no serán utilizados por el almacén de preferencias del plug-in. El lugar correcto para inicializar los valores predeterminados es la clase principal de Plugin misma. De otra manera, todas las preferencias que están en sus valores predeterminados serán retornadas por el almacén de preferencias como 0 o nulas.

Así, la clase de página de preferencias se vuelve mucho más simple, como se muestra en el Listado 10, y el método initializeDefaultPreferences es añadido a la clase PluginUi como se muestra en el Listado 11. Note que los valores predeterminados para cada preferencia son definidos por la estructura de las preferencias, no por la clase de plug-in ni por la clase de página de preferencias.

Listado 10. Página de preferencias para el plug-in de HSQLDB
public class HSQLDBPreferencePage
    extends FieldEditorPreferencePage
    implements IWorkbenchPreferencePage {

    public HSQLDBPreferencePage() {
        super(GRID);
        setPreferenceStore(PluginUi.getDefault().getPreferenceStore());
        setDescription("Connection parameters for the embedded HSQLDB server");
    }
    
    public void createFieldEditors() {
        addField(new IntegerFieldEditor(HsqldbParams.P_PORT, 
                "&TCP Port:",
                getFieldEditorParent()));
        addField(new StringFieldEditor(HsqldbParams.P_USER,
                "Administrator &User:",
                getFieldEditorParent()));
        addField(new StringFieldEditor(HsqldbParams.P_PASSWD,
                "Administrator &Password:",
                getFieldEditorParent()));
    }
    
    public void init(IWorkbench Workbench) {
    }
}
Listado 11. Métodos cambiados desde la clase Plugin generada
    public void shutdown() throws CoreException {
        // shuts down the server if running
        Thread server = getHsqldbServer();
        if (server != null && server.isAlive()) {
        		 try {
                HsqldbUtil.stopHsqldb();
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
        super.shutdown();
    }

    protected void initializeDefaultPreferences(IPreferenceStore store) {
        super.initializeDefaultPreferences(store);
        HsqldbParams params = new HsqldbParams();
        store.setDefault(HsqldbParams.P_PORT, params.port);
        store.setDefault(HsqldbParams.P_USER, params.user);
        store.setDefault(HsqldbParams.P_PASSWD, params.passwd);
    }

Proporcionar retroalimentación al usuario

Como el conjunto de plug-ins no proporciona una vista ni un editor para la Estación de Trabajo, existen formas limitadas para proporcionar retroalimentación de usuario en las acciones. Podemos utilizar la línea de estado de la ventana de la Estación de Trabajo y también un SWT MessageDialog , de forma que los eventos importantes (principalmente errores) no sean perdidos por el usuario.

El modelo de visibilidad y habilitación para las acciones de Estación de Trabajo está enfocado en la selección de recursos de la estación de trabajo, pero la mayoría de las acciones de plug-in (iniciar el servidor de HSQLDB, detenerlo e iniciar el Gestor de Base de Datos) no dependen de la selección de recursos, sino de si el servidor está o no en ejecución -- condiciones que deben ser explícitamente verificadas por cada acción run .

Advertencia: las clases de plug-in y acción no son instanciadas hasta que sea absolutamente requerido para reducir los requisitos de memoria de la Estación de Trabajo. El contenido del archivo de manifiesto es utilizado para presentar opciones de menú y para habilitarlas/inhabilitarlas, pero como el servidor de HSQLDB no es un recurso de lugar de trabajo, no puede habilitar acciones. Es posible, como se describe para el código de manifiesto en el Listado 2, (vea el elemento <enablement> ) habilitar/inhabilitar una acción con base en la activación del plug-in, de forma que en la inicialización sólo la acción "Start HSQLDB server" esté habilitada, pero después de eso no existe una forma fácil para, digamos, inhabilitar esta acción si el servidor ya está en ejecución y después volver a habilitarla cuando se detenga.

Note el código utilizado para poner un indicador de espera en la ventana de la Estación de Trabajo y el código utilizado para establecer el mensaje de la línea de estado. Estos no son fáciles de encontrar en la documentación de PDE o los artículos de Eclipse.org.


Toques finales

La clase de plug-in altera temporalmente el método shutdown de forma que puede concluir con limpieza el servidor cuando la Estación de Trabajo es cerrada y ya hemos terminado. Por supuesto, un conjunto completo de plug-ins requeriría tareas adicionales que no están cubiertas aquí, tales como:

  • Empaquetar los dos plug-ins como un dispositivo, de forma que todos sean instalados, eliminados, habilitados e inhabilitados como una unidad.
  • Proporcionar documentos de ayuda para el plug-in mismo e incluir documentos de HSQLDB en un formato adecuado para el gestor de ayuda de la Estación de Trabajo.

Conclusión

Este artículo mostró cómo crear un conjunto de plug-ins que lleven la base de datos de HSQLDB en la Estación de Trabajo de Eclipse, añadiendo la capacidad de iniciar y detener el servidor de base de datos, así como ejecutar sentencias SQL y scripts. Hemos visto cómo el PDE hace que la creación de este plug-in sea fácil, mediante asistentes y editores para la mayoría de las tareas, dejando al desarrollador con poco más que la tarea de crear el código que realmente implemente la funcionalidad deseada.

En la siguiente parte de esta serie, aprenderá cómo aprovechar los dispositivos de la Estación de Trabajo para añadir valor al desarrollo de HSQLDB, en lugar de simplemente ejecutar herramientas previamente existentes.


Descargar

DescripciónNombretamaño
Código de ejemploos-echsql/hsqldbplugin1.zip---

Recursos

Comentarios

developerWorks: Ingrese

Los campos obligatorios están marcados con un asterisco (*).


¿Necesita un IBM ID?
¿Olvidó su IBM ID?


¿Olvidó su Password?
Cambie su Password

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


La primera vez que inicie sesión en developerWorks, se creará un perfil para usted. La información en su propio perfil (nombre, país/región y nombre de la empresa) se muestra al público y acompañará a cualquier contenido que publique, a menos que opte por la opción de ocultar el nombre de su empresa. Puede actualizar su cuenta de IBM en cualquier momento.

Toda la información enviada es segura.

Elija su nombre para mostrar



La primera vez que inicia sesión en developerWorks se crea un perfil para usted, teniendo que elegir un nombre para mostrar en el mismo. Este nombre acompañará el contenido que usted publique en developerWorks.

Por favor elija un nombre de 3 - 31 caracteres. Su nombre de usuario debe ser único en la comunidad developerWorks y debe ser distinto a su dirección de email por motivos de privacidad.

Los campos obligatorios están marcados con un asterisco (*).

(Por favor elija un nombre de 3 - 31 caracteres.)

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


Toda la información enviada es segura.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=90
Zone=tecnologia Java
ArticleID=852026
ArticleTitle=Eclipse y HSQLDB: Incorporación de un servidor de base de datos relacional en Eclipse, Parte 1
publish-date=12172012