6. Record management system. 6.1. Descripcin del captulo Hasta ahora nuestras aplicaciones perdan toda la informacin tras su ejecucin. Es cierto tambin, que no hemos necesitado guardar ningn tipo de datos, pero pinsese en la realizacin de, por ejemplo, una agenda telefnica en la que guardaramos los nmeros de telfonos y direcciones de unas determinadas personas. Aqu se hara imprescindible el poder guardar toda la informacin introducida (nombres, telfonos y direcciones) en el dispositivo MID para posteriormente poder consultarla o modificarla. Pues bien, MIDP proporciona un mecanismo a los MIDlets que les permite almacenar datos de forma persistente para su futura recuperacin. Este mecanismo est implementado sobre una base de datos basada en registros que llamaremos Record Management System o RMS (Sistema de gestin de registros). Comenzaremos viendo en este captulo conceptos bsicos sobre cmo se realiza el almacenamiento persistente o sobre cmo es el modelo de datos usado por el RMS. Veremos qu operaciones bsicas podemos realizar a travs de la clase RecordStore y tambin qu otras operaciones ms avanzadas podemos realizar con el resto de clases que estn dentro del paquete javax.microedition.rms. 6.2. Conceptos Bsicos El sistema de gestin de registros o RMS, como lo llamaremos de ahora en adelante, nos permite almacenar informacin entre cada ejecucin de nuestro MIDlet. Esta informacin ser guardada en el dispositivo en una zona de memoria dedicada para este propsito. La cantidad de memoria y la zona asignada para ello depender de cada dispositivo. 6.2.1. Modelo de datos Como ya se ha dicho, el RMS est implementado en una base de datos basada en registros (ver Figura 6.1).
Los MIDlets son los encargados de crear los Record Stores para comunicarse con ellos. Estos Record Stores quedan almacenados en el dispositivo y pueden ser accedidos por cualquier MIDlet que pertenezca a la misma suite (ver Figura 6.2).
6.2.2. Record Stores Las propiedades de estos almacenes de registros son: 1. Cada Record Store est compuesto por cero o ms registros. 2. Un nombre de Record Store es sensible a maysculas y minsculas y est formado por un mximo de 32 caracteres UNICODE. 3. Dentro de una suite no pueden coexistir dos Record Stores con el mismo nombre. 4. Si una suite de MIDlets es borrada del dispositivo MID, todos los Record Stores pertenecientes a esa suite se borrarn. 5. Es posible que un MIDlet acceda a un Record Store creado por otra suite, siempre que sta de permiso para ello. Un Record Store tal como su nombre indica es un almacn de registros. Estos registros son la unidad bsica de informacin que utiliza la clase RecordStore para almacenar datos. Cada uno de estos registros est formado por dos unidades: Un nmero identificador de registro (Record ID) que es un valor entero que realiza la funcin de clave primaria en la base de datos. Un array de bytes que es utilizado para almacenar la informacin deseada. En la Figura 6.3 se ilustra la estructura de un Record Store:
Adems de un nombre, cada Record Store tambin posee otros dos atributos: Nmero de versin: Es un valor entero que se actualiza conforme vayamos insertando, modificando o borrando registros en el Record Store. Podemos consultar este valor invocando al mtodo RecordStore.getVersion(). Marca temporal: Es un entero de tipo long que representa el nmero de milisegundos desde el 1 de enero de 1970 hasta el momento de realizar la ltima modificacin en el Record Store. Este valor lo podemos obtener invocando al mtodo RecordStore.getLastModified(). As, la estructura de un Record Store se aproxima ms a la Figura 6.4.
6.3. Operaciones con Record Stores Una vez vista la teora, pasemos a la prctica. Ya sabemos qu es un Record Store y como est formado. En este punto veremos la clase javax.microedition.rms.RecordStore y todas las operaciones que nos permitan realizar sus mtodos. 6.3.1. Creacin de un Record Store La clase RecordStore no dispone de ningn constructor, pero posee el mtodo esttico: static RecordStore openRecordStore(String name, boolean createIfNeccesary) Este mtodo nos abre el Record Store con el nombre pasado como parmetro o nos crea uno si no existe cuando el parmetro createIfNeccesary es true. Adems, existen otras dos versiones alternativas de este mtodo: static RecordStore openRecordStore(String name, boolean createIfNeccesary, int autorizacin, boolean writable) static RecordStore openRecordStore(String name, String vendorName, String suiteName) El primero de ellos usa los siguientes parmetros: autorizacin: AUTHMODE_PRIVATE: Slo permite el acceso al Record Store a la MIDlet suite que lo cre. AUTHMODE_ANY: Permite el acceso a cualquier MIDlet del dispositivo. Este modo hay que usarlo con mucho cuidado ya que podra provocar problemas de privacidad y seguridad. writable: Indicamos si el Record Store puede ser modificado por cualquier MIDlet que pueda acceder a l. Estos parmetros slo tienen efecto si estamos creando un Record Store. Si ste ya estaba creado, estos parmetros se ignorarn. El segundo mtodo lo usaremos para abrir un Record Store que est asociado a alguna MIDlet suite especificada por los parmetros vendorName y suiteName. El acceso vendr limitado por el tipo de autorizacin del Record Store cuando fue creado (vase mtodo anterior). Cundo terminemos de usar el Record Store, hay que cerrar la comunicacin con l. Esto lo haremos mediante el mtodo: public void closeRecordStore() throws RecordStoreNotFoundException, RecordStoreException Para cerrar correctamente la comunicacin con un Record Store, es necesario invocar este mtodo tantas veces como llamadas se haya realizado al mtodo openRecordStore(). En la Tabla 6.1 podemos ver algunos mtodos que nos proporcionan operaciones generales con los Record Stores.
6.3.2. Manipulacin de registros Una vez creado o abierta la comunicacin con el Record Store, podemos leer, escribir, modificar o borrar registros a nuestro gusto. Para ello, usaremos los mtodos de la clase RecordStore que se ven en la Tabla 6.2.
6.4. Operaciones avanzadas con Record Stores La clase RecordStore nos proporciona algunas interfaces que nos facilitan el trabajo a la hora de manipular registros. Bsicamente, vamos a ver como estas interfaces nos ayudan a la hora de navegar por los registros de un Record Store, realizar bsquedas en ellos y ordenaciones. 6.4.1. Navegacin a travs de un Record Store En los ejemplos anteriores hemos usado un simple bucle para movernos entre los distintos registros de nuestro Record Store: for (int i=1;i<=rs.getNumRecords();i++){ longitud = rs.getRecordSize(i); registro = rs.getRecord(i); System.out.println(Registro +i+: + new String(registro,0,longitud)); } Sin embargo, la clase RecordStore nos proporciona la interfaz RecordEnumeration que nos facilita esta tarea. Esta interfaz posee los mtodos que aparecen en la Tabla 6.3.
Haciendo uso de esta interfaz podemos sustituir el bucle anterior por algo como lo siguiente: RecordEnumeration re = rs.enumerateRecords(null,null,false); while (re.hasNextElement()){ registro = re.nextRecord(); //Realizo las operaciones que quiera ... } Como vemos, la navegacin por los registros usando RecordEnumeration es mucho ms intuitiva y nos permite realizar acciones como movernos hacia delante o hacia atrs de una manera muy sencilla. Vamos a fijarnos en los parmetros que le pasamos al mtodo enumerateRecords(). Como podemos ver en la tabla 6.1, hemos de pasarle como primer parmetro una referencia a un RecordFilter y como segundo, otra a un RecordComparator. Nosotros hemos sustituido ambas referencias por null con lo que conseguiremos un objeto RecordEnumeration con la misma estructura de registros que el Record Store original. El tercer parmetro indica si queremos que los ndices se actualicen en el caso de que se produzca alguna accin en el Record Store por cualquier otro MIDlet mientras trabajamos con l. 6.4.2. Bsqueda de registros Para realizar una bsqueda eficiente de registros en un Record Store vamos a utilizar la interfaz RecordFilter. Esta interfaz se encarga de devolver al RecordEnumeration nicamente los registros que coincidan con un determinado patrn de bsqueda. Para usar esta interfaz hemos de implementar necesariamente el mtodo: public boolean matches(byte [] candidato) que se encarga de comparar el registro candidato pasado como parmetro con el valor que queremos buscar y devolvemos true en caso de que coincidan. 6.4.3. Ordenacin de registros La ordenacin de registros se realiza a travs del interfaz RecordComparator. Esta interfaz funciona bsicamente igual que el RecordFilter. Existe un mtodo public int compare(byte[] reg1, byte[] reg2) que ha de ser implementado obligatoriamente. Este mtodo es el encargado de realizar la comparacin entre los campos que deseemos de los registros y el entero que nos devuelve nos indica si reg1 va antes o despus que reg2. El valor devuelto por este mtodo puede ser: EQUIVALENT: Los registros pasados al mtodo compare son equivalentes. FOLLOWS: El primer registro sigue al segundo. PRECEDES: El primer registro precede al segundo.