Thursday, April 01, 2010

API Preferences

Información General

Las aplicaciones requieren datos de preferencia y configuración para adaptarse a las necesidades de diferentes usuarios y ambientes. El paquete java.util.prefs ofrece un camino para que las aplicaciones almacenen y recuperen preferencias y datos de configuración tanto como de usuarios como del sistema. Los datos son almacenados persistente mente sobre una implementación dependiente de un almacén. Existen dos arboles separados de preferencias, uno es para preferencias de usuario y otro es para preferencias del sistema.

Todos los métodos que modifican los datos de preferencias, tienen permitido operar de una manera asíncrona. Ellos pueden retornar inmediatamente, y los cambios eventualmente serán propagados al almacén de persistencia. El método flush puede ser utilizado para forzar a actualizar el almacén de datos.

Los métodos en la clase Preferentes pueden ser invocados concurrente mente por múltiples hilos en una sola JVM sin la necesidad de tener una sincronizacion externa, y el resultado sera equivalente a algunas ejecuciones de manera serial. Si esta clase es utilizada por múltiples JVMs que almacenan sus datos de preferencias en el mismo almacén de datos, los datos almacenados no estarán corruptos, pero no se garantiza que los datos sean consistentes para los datos de preferencias.

Comparando la API Preferences a otros Mecanismos


Antes de la introducción de la API Preferences, los desarrolladores podían escoger en administrar las preferencias y los datos de configuración de una manera ad hoc fashion, al utilizar la API Properties o la API JNDI como se describe a continuación.

A menudo, las preferencias y los datos de configuración eran almacenado en archivos de propiedades, accedido a través de la API java.util.Properties. Sin embargo, no existen estadares de donde dichos archivos deberían estar en el disco, o como serian ellos llamados. Utilizando este mecanismo, es extremadamente dificultoso en hacer copias de seguridad en los datos de preferencias de un usuario, o transferir esta información de una maquina a otra. A medida como el numero de aplicaciones crecía, la posibilidad de conflictos en nombre de archivos crecía. También, este mecanismo no ayudaba entre las plataformas en donde caía el disco duro, o en donde es deseable que los datos estuvieran almacenado en un almacén de datos externo (como un gran empresarial servicio de directorio LDAP).

Menos frecuente, los desarrolladores almacenaban preferencias de usuario y configuración de datos en servicio de directorio, accedido atravez de la API interfaz de nombrado java y directorio (JNDI). A diferencia de la API Properties, JNDI permite a los usuarios arbitrariamente almacenar datos(back-end neutrality). Mientras que JNDI es extremadamente poderoso, es también bastante grande, consiste de 5 paquetes y 83 clases. JNDI no ofrece políticas de donde en el espacio de nombres de directorio los datos de preferencias deberían ser almacenados, o en cual nombre de espacio.

Ni Properties ni JNDI ofrecen una simple, no ambigua, back-end neutral facilidad de administración de preferencias. La API Preferences ofrece dicha facilidad, combinando la simplicidad de Properties con la neutralidad back-end de JNDI. Este ofrece suficiente política integrada para prevenir conflictos de nombres, coherencia de acogida, y fomentar la robustez frente a la inaccesibilidad al almacén de datos.

Notas de Uso

El material contenido en esta sección no es parte de la especificación de la API Prefereces, este pretende ofrecer algunos ejemplos de como las la API Preferences debería ser usado.

Obteniendo objetos de Preferencia para una clase envolvente

Los siguientes ejemplos ilustran de como se deberían obtener objetos de Preferences (system y user) pertinentes a la clase envolvente. Estos ejemplos deberían trabajar solo dentro de métodos de instancia.

Note que los campos finales estáticos, a diferencias de literales String, son utilizados para los nombres key (NUM_ROWS y NUM_COLS). Esto reduce la probabilidad de bugs de rutinas, de errores tipografía en los nombres key.

Note también que razonables default son ofrecidos por cada una de los valores de preferencias obtenidos. Estos defaults serán retornado si ningún valor de preferencia han sido seteados, o si el almacén de datos es inaccesible.

package com.acme.widget;
import java.util.prefs.*;

public class Gadget {
// Preference keys for this package
private static final String NUM_ROWS = "num_rows";
private static final String NUM_COLS = "num_cols";

void foo() {
Preferences prefs = Preferences.userNodeForPackage(this);

int numRows = prefs.getInt(NUM_ROWS, 40);
int numCols = prefs.getInt(NUM_COLS, 80);

...
}
}
El anterior ejemplo obtiene las preferencias del usuario. Si un solo, valor por sistema fuese deseado, la primera line en foo debería ser remplazada por:

Preferences prefs = Preferences.systemNodeForPackage(this);
Obteniendo Objetos de Preferencias para un método estático

Los ejemplos en esta sección ilustran de como obtener objetos de Preferencias pertinentes a la clase envolvente, y trabaja dentro métodos de instancia. En un método estático (o inicializado estático), se necesita explícitamente ofrecer el nombre del paquete:

static String ourNodeName = "/com/acme/widget";

static void foo() {
Preferences prefs = Preferences.userRoot().node(ourNodeName);

...
}

Siempre es aceptable obtener objetos preferencias del sistema una vez, en un inicializados estático, y utilizarlo cuando las preferencias del sistema son requeridos:

static Preferences prefs = Preferences.systemRoot().node(ourNodeName);

En general, es aceptable hace la misma cosa para los objetos de preferencias de usuarios, pero no si el código en cuestión sera utilizado en un servidor, en donde múltiples usuarios estarán corriendo concurrente mente o de manera serial. En dichos sistemas, userNodeForPackeage y userRoot retornaran el nodo apropiado para la llamada del usuario, ademas es critico que las llamadas a userNodeForPackage o userRoot sean hechas desde el hilo apropiado en el momento apropiado. Si una pieza de código puede eventualmente ser utilizada en dicho ambiente del servidor, está bien, practica conservativa para obtener objetos de preferencias de usuario imediatamente antes de que ellos sean usados, como en el ejemplo anterior.

Actualización Atomica

La API Preferences no ofrece transacciones como las base de datos en donde múltiples preferencias son modificadas atomicamente. Ocasionalmente, es necesario modificar dos o mas preferencias como unidad. Por ejemplo, supongamos que se están almacenando las coordenadas x y y en donde una ventana esta colocada. La única manera de realizar la atomicidad es almacenar ambos valores en una sola preferencia. Muchas codificación son posibles, por ejemplo:

int x, y;
...
prefs.put(POSITION, x + "," + y);

Donde un componente de preferencia es leído, este debe ser decodificado.

static int X_DEFAULT = 50, Y_DEFAULT = 25;
void baz() {
String position = prefs.get(POSITION, X_DEFAULT + "," + Y_DEFAULT);
int x, y;
try {
int i = position.indexOf(',');
x = Integer.parseInt(coordinates.substring(0, i));
y = Integer.parseInt(position.substring(i + 1));
} catch(Exception e) {
// Value was corrupt, just use defaults
x = X_DEFAULT;
y = Y_DEFAULT;
}
...
}

Fuente

No comments: