Trabajar con los Datos
Este capítulo muestra cómo utilizar extensión para añadir funcionalidades específicas de la aplicacion a nuestra aplicación
JAXB. Continuaremos con el CheckbookApp que creamos en el capítulo anterior. En este
capítulo, crearemos una nueva clase, llamada CheckbookBalance. Esta nueva clase extenderá la clase
Checkbook generada y contendrá un método que añada las transacciones al
checkbook y calcule el nuevo balance. La clase CheckbookApp
llama a este nuevo método para añadir las transacciones de Marzo y Abril (representadas por los árboles de contenido que
creamos en el capítulo anterior) al checkbook. En este capítulo, trabajaremos con el documento
checkbook.xml, que representa el libro de cheques. La lista de
transacciones y el balance de la cuenta.
El Documetno XML de Ejemplo: checkbook.xml
El documento de checkbook.xml define un
checkbook, que contiene un conjunto de transacciones y un balance, así que en vez de definir
transactions como el elemento raíz, este documento define el elemento
checkbook como el elemento raíz, que contiene la lista de transacciones y el balance:
<?xml version="1.0" encoding="US-ASCII"?>
<checkbook>
<transactions>
<deposit category=salary>
<date>02-09-2001</date>
<name>Me</name>
<amount>2500.00</amount>
</deposit>
<check number="90" category="other">
<date>02-12-2001</date>
<name>My Local Bookstore</name>
<amount>34.95</amount>.
<pending/>
<memo>Dukes Book</memo>
</check>
<check number="91" category="rent">
<date>02-28-2001</date>
<name>Landlord</name>
<amount>1500.00</amount>
<void/>
<memo>February</memo>
</check>
</transactions>
<balance>50000.00</balance>
</checkbook>
Observa que checkbook sólo tiene las transacciones de Febrero. Este capítulo mostrará cómo
añadir las transacciones de Marzo y de Abril al checkbook y poner al día el balance. El
fichero checkbook.xml también está situado en el directorio
examples/checkbook de la instalación.
Configurar la Clase CheckbookBalance
Para crear la clase CheckbookBalance:
- Creamos un fichero llamado CheckbookBalance.java.
- Importamos estos paquetes:
import java.io.*;
import java.util.*;
import java.math.*;
- Declaramos la clase CheckbookBalance para que extienda Checkbook:
public class CheckbookBalance extends Checkbook {
}
- Dentro de CheckbookBalance, creamos el método balanceCheckbook:
public class CheckbookBalance extends Checkbook {
void balanceCheckbook(Transactions trans) throws Exception {
}
}
Este método contendrá todo el código para agregar transacciones al checkbook y para
calcular el nuevo balance. La clase CheckbookApp pasará la lista completa de transacciones
que creamos en la sección anterior al método balanceCheckbook.
Extender las clases Derivadas
En el capítulo Construir Representaciones de Datos, aprendimos cómo utilizar
directamente las clases derivadas. Otra manera de usar las clases derivadas es con la extensión. La extensión implica la
subclasificación de una clase derivada para proporcionar funciones específicas. Esta sección explica la extensión mostrando
cómo balancear el checkbook y agregar las entradas de transacciones al
checkbook.
Desempaquetar
Antes de que podamos realizar los cálculos, necesitamos desempaquetar el fichero que contiene las transacciones en un
árbol de contenido, como hizimos en la sección Desempaquetamiento del capítulo anterior. Sin embargo, este vez estamos
extendiendo checkbook en vez de utilizarlo directamente, lo que significa que desempaquetamos
un objeto CheckbookBalance, no un objeto Checkbook. Si no
especificamos que CheckbookBalance debe ser desempaquetado, el proceso de desempaquetamiento
devuelve un objeto Checkbook, no un objeto CheckbookBalance.
Para solucionar este problema, necesitamos registrar CheckbookBalance con un
Dispatcher.
Despachar
Un dispatcher asocia nombres de elementos con nombres de clases y nombres de sublases con nombres
de clases. El proceso de desempaquetamiento comienza con la llamada de los métodos unmarshal de
un dispatcher. Un dispatcher por defecto desempaqueta contenido XML
XML en ejemplares de las clases generadas. Para nuestro ejemplo, esto significa que el método
unmarshal devolvería un checkbook, no un
CheckbookBalance. Para devolver un CheckbookBalance, necesitamos
registrar CheckbookBalance con el Dispatcher. Para hacer esto:
- En la parte superior de CheckbookApp.java , inicializamos un objeto
CheckbookBalance:
public static CheckbookBalance chBook = new CheckbookBalance();
- Creamos un nuevo método en CheckbookApp.java llamado unmarshalSubclass:
public static void unmarshalSubclass() throws Exception{}
- En este nuevo método, adquirimos el Dispatcher por defecto de Checkbook:
Dispatcher d = Checkbook.newDispatcher();
- Registramos CheckbookBalance con el Dispatcher devuelto:
d.register(Checkbook.class, CheckbookBalance.class);
Este método registra la subclase CheckbookBalance con el Dispatcher
para que pueda desempaquetar un CheckbookBalance en lugar de un Checkbook.
- Llamamos a unmarshalSubclass desde el método main:
unmarshalSubclass();
Desempaquetar las Subclases
Como registramos CheckbookBalance con un Dispatcher,
necesitamos llamar al método unmarshal del dispatcher, no al
método unmarshal del objeto CheckbookBalance. Para desempaquetar
CheckbookBalance:
- En el método unmarshalSubclass, leemos checkbook.xml en un
FileInputStream:
File checkbookNew = new File(checkbook.xml);
FileInputStream fNewIn = new FileInputStream(checkbookNew);
- Forzamos el objeto devuelto por el método unmarshal a un objeto
CheckbookBalance:
try{
chBook = (CheckbookBalance)(d.unmarshal(fNewIn));
}
finally {
fNewIn.close();
}
La siguiente sección demuestra cómo implementar los cálculos del balance del libro de cheques en
CheckbookBalance.java.
Añadir Funcionalidad
El fichero CheckbookBalance.java sólo contiene un método:
balanceCheckbook. Esta sección muestra cómo implementar
balanceCheckbook para calcular el nuevo balance basándose en el balance del més anterior y
añadiendo las transacciones de Marzo y Abril. Para implementar el método balanceCheckbook
en la clase CheckbookBalance:
- Obtenemos el balance actual grabado en nuestro checkbook:
BigDecimal balance = this.getBalance();
- Obtenemos la lista de entradas de los objetos Transactions qu se pasa a este método:
List tEntries = trans.getEntries();
- Inicializamos un BigDecimal para guardar la cantidad de cada transación:
BigDecimal amt;
- Creamos un bucle para iterar a través de la lista de transaciones y obtener la cuantía de cada una:
for (ListIterator i = tEntries.listIterator(); i.hasNext(); ) {
Entry entry = (Entry)i.next();
amt = entry.getAmount();
- Si la entrada es un Deposit, añadimos la cuantía del depósito al
balance del checkbook; de otro modo, restamos la cuantía de
la transación al balance:
if (entry instanceof Deposit){
balance = balance.add(amt);
}
else {
balance = balance.subtract(amt);
}
- después de recalcular el balance basado en la transacción, añadimos la transación a la lista de transaciones del
checkbook:
this.getTransactions().getEntries().add(entry);
}
- Después de haber iterado por la lista de transaciones, chequemos si el balance es negativo. Si es así, avisamos al usuario
de que está en números rojos:
if(balance.compareTo(new BigDecimal(0.00)) == -1){
System.out.println("You are overdrawn.");
}
- Imprimimos el nuevo balance y seleccionamos el balance del
checkbook al nuevo balance:
System.out.println("Your balance is: "+balance);
this.setBalance(balance);
La siguiente sección muestra cómo invocar la nueva funcionalidad en CheckbookBalance
desde CheckbookApp.java.
Usar las Nuevas Funcionalidades en Nuestra Aplicación
Esta sección muestra cómo utilizar el método balanceCheckbook de
CheckbookApp para balancear checkbook y para añadir las
transacciones a de Marzo y Abril al checkbook. La clase
CheckbookBalance está escritá de una forma genérica de modo que pueda tomar cualquier objeto
transactions y añadir las transacciones a un checkbook y calcular
el nuevo balance. Todo lo que necesitamos hacer desde neustra aplicación es llamar al método
balanceCheckbook con un objeto Transactions particular y
empaquetar el resultado en un nuevo fichero checkbook. Para poner al día el
checkbook con las nuevas transacciones y balancear:
- En el método main de la clase CheckbookApp, llamamos al
método balanceCheckbook con el objeto marchTrans:
chBook.balanceCheckbook(marchTrans);
Este objeto contiene la lista de transaciones de Marzo y Abril que creamos en la sección Añadir
Árboles de Contenido. El objeto chBook ahora contiene las transaciones y el balance
actualizados.
- Creamos un nuevo método en CheckbookApp llamado
validateAndMarshalCheckbook:
public static void validateAndMarshalCheckbook() throws Exception {}
- Como editamos el árbol de contenido del checkbook, realizamos la validación sobre
chBook dentro del nuevo método que acabamos de crear:
chBook.validate();
- Creamos un nuevo fichero XML para el checkbook actualizado:
File checkbook_new = new File("checkbook_new.xml");
FileOutputStream fCOut = new FileOutputStream(checkbook_new);
- Empaquetamos el checkbook actualizado en el nuevo fichero XML:
try {
chBook.marshal(fCOut);
}
finally {
fCOut.close();
}
- Llamamos a validateAndMarshalCheckbook desde el método main
de CheckbookApp:
validateAndMarshalCheckbook();
- Grabamos CheckbookBalance.java y CheckbookApp.java y recompilamos:
javac *.java
- Ejecutamos de nuevo CheckbookApp:
java CheckbookApp
Nuestro fichero checkbook_new.xml tiene un balance actualizado de $48065.72 y
contiene nuestras transaciones de Febrero, Marzo y Abril.