No es un bug, es una característica no documentada

27/10/15

Procesos y servicios. Hilos. Applets

Un Applet es una aplicación Java que se incrusta en una página HTML, aunque los navegadores, por defecto, no permiten este tipo de programas en las webs porque son una brecha de seguridad.

Estos applets se extienden de la clase Applet, así que la creación de los hilos, en caso de que queramos hacerlo todo en una única clase, habrá que dejarlo a Runnable.

Un ejemplo sería este Applet para crear un reloj:

import java.applet.Applet;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.text.SimpleDateFormat;
import java.util.Calendar;

public class Reloj extends Applet implements Runnable {

     private Thread hilo = null;    //hilo
     private Font fuente; //Tipo de letra para la hora
     private String horaActual = "";
    
     public void init(){
          fuente = new Font ("Verdana", Font.BOLD, 26);
     }//fin de init
    
     public void start(){
          if(hilo == null){
                hilo = new Thread(this);
                hilo.start();
          }
     }//fin de start
    
     @Override
     public void run() {
          Thread hiloActual = Thread.currentThread();
          while (hilo == hiloActual){
                SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
                Calendar cal = Calendar.getInstance();
                horaActual = sdf.format(cal.getTime());
                repaint(); //se actualiza el contenido del Applet
                try {
                     Thread.sleep(1000);
                } catch (InterruptedException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                }
          }
     }//fin de run

     public void paint (Graphics g){
          g.clearRect(1, 1, getSize().width, getSize().height);
          setBackground(Color.yellow);   //Color de fondo
          g.setFont(fuente);
          g.drawString(horaActual, 20, 50);//Muestra la hora
     }//fin de paint
    
     public void stop(){
          hilo=null;
     }
}

O este otro para realizar un contador:

import java.applet.Applet;
import java.awt.Button;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class ContadorApplet extends Applet implements Runnable, ActionListener {
     private Thread h;
     long CONTADOR = 0;
     private boolean parar;
     private Font fuente;
     private Button b1,b2; //botones del Applet
    
     public void start() {}
    
     public void init() {
    
          setBackground(Color.yellow);//color de fondo
          add(b1=new Button("Iniciar contador"));
          b1.addActionListener(this);
          add(b2=new Button("Parar contador"));   
          b2.addActionListener(this);
          fuente = new Font("Verdana", Font.BOLD, 26);//tipo letra
    
     }
         
    
    
     public void run() {
    
          parar=false;
          Thread hiloActual = Thread.currentThread();
          while (h == hiloActual && !parar) {
                try {
                     Thread.sleep(300);
                } catch (InterruptedException e) {
                     e.printStackTrace();
                }
                repaint();
                CONTADOR++;
          }
     }
    
    
    
     public void paint(Graphics g) {
    
          g.clearRect(0, 0, 400, 400);
          g.setFont(fuente);   //fuente
          g.drawString(Long.toString((long)CONTADOR),80,100);
    
     }
    
    
    
     //para controlar que se pulsan los botones
     public void actionPerformed(ActionEvent e) {
         
          b1.setLabel("Continuar");
          if(e.getSource()==b1) //comienzo
          {
                if(h!=null && h.isAlive()) {
                }    //Si el hilo está corriendo no hago nada,
                else { //lo creo
                     h = new Thread(this);
                     h.start();
                }
          }else if(e.getSource()==b2) //parada
                parar=true;
    
     }//fin de actionPerformed
    
    
    
     public void stop() {
          h = null;
     }
    
    
}//fin applet

Pero no tiene porqué ser así. Partiendo del ejemplo anterior, podemos realizar un applet que separe el hilo en una clase aparte dentro del applet que extienda Thread. El applet que ahora no implementará Runnable, debe quedar así:

public class actividad2_2 extends Applet implements ActionListener {
class HiloContador extends Thread {
//atributos y métodos
. . .
}//fin clase
//atributos y métodos
. . .
}//fin applet

Para hacernos una idea, vamos a crear la misma aplicación de contador que antes pero que lance dos hilos y muestre dos botones para finalizarlos. Algo así



25/10/15

24/10/15

Acceso a datos. JDBC (V). Uso del ResultSet

20:03 Posted by Inazio , , No comments
El ResultSet es el objeto que representa el resultado de una consulta.
No carga toda la información en memoria, y se pueden usar para actualizar, borrar e insertar nuevas filas.

Características

Al crear un Statement, un PreparedStatement o un CallableStatement, se pueden configurar aspectos del ResultSet que devolverá al ejecutar la consulta.

createStatement(int resultSetType, int resultSetConcurrency);

prepareStatement(String SQL, int resultSetType, int resultSetConcurrency);

prepareCall(String sql, int resultSetType, int resultSetConcurrency);

resultSetType
  • ResultSet.TYPE_FORWARD_ONLY. Sólo movimiento hacia delante (por defecto).
  • ResultSet.TYPE_SCROLL_INSENSITIVE. Puede hacer cualquier movimiento pero no refleja los cambios en la base de datos.
  • ResultSet.TYPE_SCROLL_SENSITIVE. Puede hacer cualquier movimiento y además refleja los cambios en la base de datos.


resultSetConcurrency
  • ResultSet.CONCUR_READ_ONLY. Sólo lectura (por defecto).
  •  ResultSet.CONCUR_UPDATABLE. Actualizable.


Actualización de datos

rs.updateString("campo", "valor");
rs.updateInt(1, 3);
rs.updateRow();

Inserción de datos

rs.moveToInsertRow();
rs.updateString(1, "AINSWORTH");
rs.updateInt(2, 35);
rs.updateBoolean(3, true);
rs.insertRow();
rs.moveToCurrentRow();

La última línea, por cierto, mueve el cursor a la posición anterior al movimiento de inserción.

Posicionamiento del cursor

El cursor puede estar en una fila concreta, pero también puede estar en dos filas especiales.
  • Antes de la primera fila (Before the First Row, BFR)
  • Después de la última fila (After the Last Row, ALR)

Inicialmente el ResultSet está en BFR, y next() mueve el cursor hacía delante, devolviendo true si se encuentra en una fila concreta y false si alcanza el ALR.

while (rs.next()){
     String name = rs.getString("titulo");
     float price = rs.getFloat("precio");
     System.out.println(name + "\t" + price);
}


Acceso a datos. JDBC (III). Conexiones y sentencias SQL

15:46 Posted by Inazio , , No comments

Conexiones a una base de datos


Cada objeto Connection representa una conexión física con la base de datos.
Se pueden especificar más propiedades además del usuario y la contraseña al crear una conexión.
Estas propiedades se pueden especificar:
  • Codificadas en la URL (ver detalles de la base de datos)
  •  Usando métodos getConnection(…) sobrecargardos de la clase DriverManager.

Ejemplo 1
String url = "jdbc:mysql://localhost:3306/sample";
String name = "root";
String password = "pass";
Connection c = DriverManager.getConnection(url, user, password);

Ejemplo 2
String url = "jdbc:mysql://localhost:3306/sample?user=root&password=pass";
Connection c = DriverManager.getConnection(url);

Ejemplo 3
String url = "jdbc:mysql://localhot:3306/sample";
Properties prop = new Properties();
prop.setProperty("user", "root");
prop.setProperty("password", "pass");
Connection c = DriverManager.getConnection(url, prop);

Sentencias SQL

Con JDBC se pueden usar diferentes tipos de Statement.

Statement.
SQL estático en tiempo de ejecución, no acepta parámetros
Statement stmt = conn.createStatement();

PreparedStatement
Para ejecutar la misma sentencia muchas veces la “prepara”. Acepta parámetros
PreparedStatement ps = conn.prepareStatement(...);

CallableStatement
Llamadas a procedimientos almacenados.

CallableStatement s = conn.prepareCall(...);

Uso de Statement

Tiene diferentes métodos para ejecutar una sentencia.
  •  executeQuery(…). Seusa para sentencias SELECT. Devuelve un ResultSet
  • executeUpdate(…). Se usa para sentencias INSERT, UPDATE, DELETE o sentencias DDL. Devuelve el número de filas afectadas por la sentencia.
  • execute(…). Método genérico de ejecución de consultas. Puede devolver uno o más ResultSet y uno o más contadores de filas afectadas.

Uso de PreparedStatement

Los PreparedStatement se utilizan:
  • Cuando se requieren parámetros.
  • Cuando se ejecuta muchas veces la misma sentencia.
    •  La sentencia se prepara al crear el objeto.
    • Puede llamarse varias veces a los métodos execute.

PreparedStatement ps = conn.preparedStatement("INSERT INTO Libros VALUES (?, ?, ?)");
ps.setInt(1, 23);
ps.setString(2, "Bambi");
ps.setInt(3, 45);
ps.executeUpdate();

Uso de CallableStatement

Permite hacer llamadas a los procedimientos almacenados de la base de datos.
Permite parámetros de entrada IN (como el PreparedStatement), parámetros de entrada – salida INOUT y parámetros de salida OUT.

CallableStatement cstmt = conn.prepareCall("{call getEmpName (?, ?)}");
cstmt.setInt(1, 111111111);
cstmt.registerOutParameter(2, java.sql.Types.VARCHAR);
cstmt.execute();

String empName = cstmt.getString(2);

Acceso a datos .JDBC (II). Diseño de una aplicación con BD

0:19 Posted by Inazio , , No comments
Se sigue el patrón DAO (Data Access Object).

Cuando se desarrolla una aplicación con BD los detalles de la comunicación con la base de datos se implementan en una clase o módulo.

La información se gestiona como objetos definidos en una clase de Java (clase Libro, Autor…), y el sistema de persistencia (BD, XML, fichero de texto, servicio web…) se puede cambiar fácilmente.

Se pueden distribuir responsabilidades entre los integrantes del equipo de desarrollo.

Por ejemplo, vamos a implementar una sencilla aplicación Java que permita gestionar libros y autores en una base de datos.

Solo soportará listado de libros, siendo estos de todos los libros, por título o por su precio. Además, al listar los libros deberán mostrarse los autores.


Las clases a implementar deberían ser las siguientes:

Acceso a datos. JDBC (I). Introducción

0:01 Posted by Inazio , , No comments
JDBC es un interfaz orientado a objetos de Java para SQL.
Se utiliza para enviar sentencias SQL a un sistema gestor de bases de datos (DBMS).
Con JDBC tenemos que continuar escribiendo las sentencias SQL, y ni le añade ni quita potencia al SQL.

Arquitectura JDBC

La filosofía de JDBC es proporcionar transparencia al desarrollador frente al gestor de bases de datos.

JDBC utiliza un Gestor de Controladores que hace de interfaz con el controlador específico de la BD.


JDBC en MySQL

Hay que añadir la librería mysql-connector-java-x.x.x-bin.jar a nuestro proyecto.
Por ejemplo, si compilamos desde línea de comandos, añadimos el fichero a la variable del sistema CLASSPATH, y si usamos Eclipse, vamos a Project à Properties à Java Build Path à Libraries à Add External JARs…

El driver es com.mysql.jdbc.Driver y la URL para conectar a la BD es jdbc:mysql://localhost:3306/simple

Introducción a JDBC

JDBC (Java DataBase Connectivity) es la API estándar de acceso a base de datos desde Java.
Está incluida en Java SE (Standard Edition). En Java SE 6 se incluye JDBC 4.0, pero actualmente la mayoría de bases de datos soportan JDBC 3.0.

Si se desa más información se puede visitar los siguientes enlaces

Para conectarse a una base de datos concreta, es necesario su driver JDBC.
El driver es un fichero JAR que se añade a la aplicación como cualquier otra librería (no necesita instalación adicional), y la mayoría de las bases de datos incorporan un driver JDBC.

ODBC (Open DataBase Connectivity) es un estándar de acceso a base de datos desarrollado por Microsoft. Sun ha desarrollado un driver que hace de puente entre JDBC y ODBC aunque no suele usarse.

Los pasos para que una aplicación se comunique con una base de datos son:
  • Cargar el driver necesario para comprender el protocolo que usa la base de datos concreta.
  • Establecer una conexión con la base de datos, normalmente a través de red.
  • Enviar consultas SQL y procesar el resultado
  • Liberar los recursos al terminar
  • Manejar los errores que se puedan producir

Veamos el siguiente código

import java.sql.*;

public class HolaMundoBaseDatos {

     public static void main(String[] args) throws ClassNotFoundException, SQLException {
         
          Class.forName("com.mysql.jdbc.Driver");
          Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/sample", "root", "password");
         
          Statement stmt = conn.createStatement();
          ResultSet rs = stmt.executeQuery("SELECT titulo, precio FROM Libros WHERE precio > 2");
         
          while(rs.next()){
                String name = rs.getString("titulo");
                float price = rs.getFloat("precio");
                System.out.println(name + "\t" + price);
          }
         
          rs.close();
          stmt.close();
          conn.close();
     }
}

Veamos que hace este código línea por línea:

Carga del driver

Class.forName("com.mysql.jdbc.Driver");

Antes de poder conectarse a la base de datos es necesario cargar el driver JDBC, y solo hay que hacerlo una única vez al comienzo de la aplicación.
El nombre del driver debe venir especificado en la documentación de la base de datos.

Se puede elevar la excepción ClassNotFoundException si hay un error en el nombre del driver o si el fichero .jar no está correcamente en el CLASSPATH o en el proyecto.

Establecer una conexión

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/sample", "root", "password");

Las bases de datos actúan como servidores y las aplicaciones como clientes que se comunican a través de la red.

Un objeto Connection representa una conexión física entre el cliente y el servidor. Para crear una conexión se usa la clase DriverManager, especificando la URL, el nombre y la contraseña de nuestra base de datos.

El formato de la URL debe especificarse en el manual de la base de datos. En el ejemplo es una muestra de como conectar a MySQL. Por supuesto, el nombre de usuario y la contraseña también dependen de la base de datos.

Ejecutar una sentencia SQL

Statement stmt = conn.createStatement();
          ResultSet rs = stmt.executeQuery("SELECT titulo, precio FROM Libros WHERE precio > 2");

Una vez que tienes una conexión puedes ejecutar sentencias SQL.
Primero se crea el objeto Statement desde la conexión, y posteriormente se ejecuta la consulta y su resultado se devuelve como un ResultSet.

Acceso al conjunto de resultados

while(rs.next()){
String name = rs.getString("titulo");
float price = rs.getFloat("precio");
     System.out.println(name + "\t" + price);
}

El ResultSet es el objeto que representa el resultado.
No carga toda la información en memoria, internamente tiene un cursor en memoria que apunta a una fila concreta del resultado en la base de datos, por lo que hay que posicionar el cursor en cada fila y obtener toda la información de la misma.

El cursor puede estar en una fila concreta, y también puede estar en dos filas especiales:
  • Antes de la primera fila (Before de First Row, BFR)
  • Después de la última fila (After the Last Row, ALR)

Inicialmente el ResultSet está en BFR. next() mueve el cursor hacía delante, devolviendo true si se encuentra en una fila concreta y false si alcanza el ALR.


Cuando el ResultSet se encuentra en una fila concreta se pueden usar los métodos de acceso a las columnas
  •  String getString(String columnLabel)
  • String getString(int columnIndex)
  • int getInt(String columnLabel)
  • int getInt(int columnIndex)
  •  … (existen dos métodos por cada tipo)

Teniendo en cuenta que los índices empiezan en 1 y no en 0.

Liberar recursos

rs.close();
stmt.close();
conn.close();

Cuando se termina de usar una Connection, un Statement o un ResultSet es necesario liberar los recursos que necesitan.

Puesto que la información de un ResultSet no se carga en memoria, existen conexiones de red abiertas.

Métodos close():
  • ResultSet.close() – Libera los recursos del ResultSet. Se cierran automáticamente al cerrar el Statement que lo creó o al reejecutar el Statement.
  • Statement.close() – Libera los recursos del Statement.
  • Connection.close() – Finaliza la conexión con la base de datos.


Manejar los errores

throws ClassNotFoundException, SQLException

Hay que gestionar los errores apropiadamente, ya que se pueden producir excepciones ClassNotFoundException si no se encuentra el driver, o excepciones SQLException al interactuar con la base de datos. Por ejemplo:
  • SQL mal formado
  • Conexión de red rota
  • Problemas de integridad al insertar datos (claves duplicadas)

Lo que hacemos con la sintaxis anterior es dejar que el error lo gestionen en un nivel superior, pero si lo queremos controlar nosotros mismos, la sentencia del código quedaría tal que así:

import java.sql.*;

public class HolaMundoBaseDatos {

     public static void main(String[] args) {
         
          try{
                Class.forName("com.mysql.jdbc.Driver");
          }
          catch(ClassNotFoundException e){
                System.err.println("El driver no se encuentra");
                System.exit(-1);
          }
         
          Connection conn = null;
         
          try{
                conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/sample", "root", "password");
                Statement stmt = conn.createStatement();
                ResultSet rs = stmt.executeQuery("SELECT titulo, precio FROM Libros WHERE precio > 2");
               
                while(rs.next()){
                     String name = rs.getString("titulo");
                     float price = rs.getFloat("precio");
                     System.out.println(name + "\t" + price);
                }
               
                rs.close();
                stmt.close();
          }
          catch(SQLException e){
                System.err.println("Error en la base de datos" + e.getMessage());
                e.printStackTrace();
          }
          finally{
                if (conn != null){
                     try{
                          conn.close();
                     }
                     catch(SQLException e){
                          System.err.println("Error al cerrar la conexión" + e.getMessage());
                     }
                }
          }
     }
}

23/10/15

Añadir spoilers vistosos a Blogger

1:37 Posted by Inazio No comments
Desde los primeros días de esta bitácora llevo subiendo los códigos de los programas directamente, lo que provoca, aparte de unas entradas sumamente largas, que cueste un poco seguir el hilo de las explicaciones según como de extensos sean los ejemplos.

Para facilitar que todos puedan navegar mejor por las entradas de este blog, a partir de ahora los códigos se mostrarán sólo si se pulsa en botón de Mostrar | Ocultar tal y como vemos en el siguiente ejemplo



¿Cómo conseguir este efecto?

Lo primero es ir a Plantilla - Editar HTML y nos cercioramos de que en el head no tenemos agregado JQuery. En ese caso añadimos la siguiente línea

<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js' type='text/javascript'/>

(Para comprobar si tenéis JQuery hay que buscar la anterior línea en el código).

Una vez hecho eso, en cada entrada que queramos realizar un spoiler añadimos el siguiente código en la sección HTML

<input type="button" id="Spoiler1" value="Mostrar | Ocultar"/><div class="Mostrar1" style="display: none;">...Aquí el contenido que quieres ocultar...</div><script>jQuery.noConflict();jQuery(document).ready(function(){jQuery('#Spoiler1').click(function(){jQuery('.Mostrar1').slideToggle("slow");});});</script>

En caso de que quieras añadir más de un spoiler en la misma entrada, deberás cambiar las partes en rojo. Es decir, si quieres añadir una segunda, Spoiler1 pasará a ser Spoiler2 y Mostrar1 será Mostrar2.

Eso es todo lo que os quería contar. Hay otras formas de hacerlo, con CSS, JavaScript, Scriptaculous... Cualquier otra forma puedes publicarla en comentarios y así compartimos conocimientos entre todos.

¡Saludos!

22/10/15

Acceso a datos. Ejercicios (IV). Ficheros XML

18:34 Posted by Inazio , , No comments
1. Realiza las siguientes tareas:

A partir de la clase persona:
import java.io.Serializable;
public class Persona  {
                private String nombre;
                private int edad;
                public Persona(String nombre, int edad) {
                               this.nombre=nombre;
                               this.edad=edad;
                              
                }
                public Persona(){
                               this.nombre=null;
                }
                public void setNombre (String nom) { nombre=nom;}
                public void setEdad (int ed) {edad=ed;}
               
                public String getNombre() {return nombre;}
                public int getEdad() {return edad;}

}

a) Crea un fichero “FichPersona.dat”,  que almacene varios objetos persona.
b) Tomando como base el fichero anterior, crea un documento XML usando DOM.
c) Implementa una clase que permita leer el documento XML del apartado anterior.

ARCHIVO PERSONA.JAVA

import java.io.*;

public class Persona implements Externalizable{

     // Propiedades
     private String nombre;
     private int edad;
    
     // Constructor
     public Persona(){}
    
     // Métodos
     public void setNombre(String nombre){
          this.nombre = nombre;
     }
    
     public void setEdad(int edad){
          this.edad = edad;
     }
    
     public String getNombre(){
          return nombre;
     }
    
     public int getEdad(){
          return edad;
     }
    
     public void writeExternal(ObjectOutput out) throws IOException{
          out.writeObject(nombre);
          out.writeObject(edad);
     }
    
     public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{
          nombre = (String)in.readObject();
          edad = (int)in.readObject();
     }
}

ARCHIVO ESCRIBIRSINCABECERA.JAVA

import java.io.*;

public class EscribirSinCabecera extends ObjectOutputStream{

     // Constructor
     public EscribirSinCabecera(OutputStream out) throws IOException{
          super(out);
     }
         
     public EscribirSinCabecera() throws IOException, SecurityException{
          super();
     }
         
     // Métodos
     /*
      * (non-Javadoc)
      * @see java.io.ObjectOutputStream#writeStreamHeader()
      *
      * Redefino el método de escribir la cabecera para que no haga nada
      */
     protected void writeStreamHeader() throws IOException{}
}

ARCHIVO CONFIGURARXML.JAVA

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.xml.parsers.*;
import javax.xml.*;
import javax.xml.transform.*;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.*;
import org.w3c.dom.*;
import org.w3c.dom.DOMImplementation;

public class ConfigurarXML {

     // Propiedades
     Document doc = null;
    
     // Métodos
    
     // Genero un XML cargando la raíz en él
     public void crearXML(String raiz, String ruta){
          try{
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                DocumentBuilder builder = factory.newDocumentBuilder();
                DOMImplementation implementacion = builder.getDOMImplementation();
                doc = implementacion.createDocument(null, raiz, null);
                doc.setXmlVersion("1.0");
                Source source = new DOMSource(doc);
                Result result = new StreamResult(new java.io.File(ruta));
                guardarCambiosXML(source, result);
          }
          catch(Exception e){
                e.printStackTrace();
          }
     }
    
     public int anadirDOM(String nombre, String edad, String ruta){
          try{
                Node nNombre = doc.createElement("Nombre");
                Node nNombreTexto = doc.createTextNode(nombre);
                nNombre.appendChild(nNombreTexto);
                Node nEdad = doc.createElement("Edad");
                Node nEdadTexto = doc.createTextNode(edad);
                nEdad.appendChild(nEdadTexto);
               
                Node nPersona = doc.createElement("Persona");
                nPersona.appendChild(nNombre);
                nPersona.appendChild(nEdad);
               
                Node raiz = doc.getChildNodes().item(0);
                raiz.appendChild(nPersona);
               
                Source source = new DOMSource(doc);
                Result result = new StreamResult(new java.io.File(ruta));
                guardarCambiosXML(source, result);
                return 0;
          }
          catch(Exception e){
                e.printStackTrace();
                return -1;
          }
     }
    
     // Convierte el Document a fichero XML
     public void guardarCambiosXML(Source fuente, Result salida){
          try{
                Transformer t = TransformerFactory.newInstance().newTransformer();
                t.transform(fuente, salida);
          }
          catch(Exception e){
                e.printStackTrace();
          }   
     }
    
     public String leerXML(String ruta){
          File archivo = new File(ruta);
          abrirDoc(archivo);
          String datosNodo[] = null;
          String salida = "";
          Node n;
         
          // Obtengo el primer hijo del DOM
          Node raiz = doc.getFirstChild();
          // Listo todos los nodos hijos de raiz
          NodeList listado = raiz.getChildNodes();
         
          for(int i = 0; i < listado.getLength(); i++){
                n = listado.item(i);
                datosNodo = procesarPersona(n);
                salida = salida + "Nombre: " + datosNodo[0];
                salida = salida + "\n" + "Edad: " + datosNodo[1];
                salida = salida + "\n\n";
          }
         
          return salida;
     }
    
     protected String[] procesarPersona(Node n){
          String datos[] = new String[2];
          Node tmp = null;
          int contador = 0;
         
          // Hijos del libro
          NodeList nodos = n.getChildNodes();
          for(int i = 0; i < nodos.getLength(); i++){
               tmp = nodos.item(i);
               
                if (tmp.getNodeType() == Node.ELEMENT_NODE){
                     // Accedo al noto TEXT hijo de tmp para obtener nombre y edad
                     datos[contador] = tmp.getChildNodes().item(0).getNodeValue();
                     contador++;
                }
          }
         
          return datos;
     }
    
     protected void abrirDoc(File f){
          doc = null;
         
          try{
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                factory.setIgnoringComments(true); // No contempla comentarios
                factory.setIgnoringElementContentWhitespace(true); // Ignoro los espacios en blanco
                DocumentBuilder b = factory.newDocumentBuilder();
                doc = b.parse(f);
          }
          catch(Exception e){
                e.printStackTrace();
          }
     }
}

ARCHIVO ACCIONES.JAVA

import java.io.*;
import java.util.Scanner;

public class Acciones {

     // Propiedades
     Persona p = new Persona();
     ConfigurarXML c = new ConfigurarXML();
    
     // Constructor
     public Acciones(){}
    
     // Métodos
    
     private void generarPersona(){
          Scanner sc = new Scanner(System.in);
         
          System.out.println("Generador de personas");
          System.out.println("Escribe nombre");
          p.setNombre(sc.nextLine());
          System.out.println("Escribe edad");
          p.setEdad(Integer.parseInt(sc.nextLine()));
          sc.close(); // Cierro el scanner
     }
    
     public void escribirDat() throws IOException, ClassNotFoundException{
          File people = new File("personas.dat");
         
          generarPersona();
          // Escribir en fichero
          if(people.exists()){
                EscribirSinCabecera salida = new EscribirSinCabecera(new FileOutputStream("personas.dat", true));
                p.writeExternal(salida);
               salida.close();
          }
          else{
                ObjectOutputStream salida = new ObjectOutputStream(new FileOutputStream("personas.dat", true));
                p.writeExternal(salida);
                salida.close();
          }
     }
    
     // Agrego datos al xml conforme voy leyendo
     public void cargarDatEnXML(String ruta) throws IOException, ClassNotFoundException{
          boolean finFichero = false;
          File f = new File(ruta);
          ObjectInputStream entrada = new ObjectInputStream(new FileInputStream("personas.dat"));
         
          // Machaco el anterior (en caso de que exista) para no duplicar datos
          c.crearXML("Gente", ruta);
         
          do{
                try{
                     p.readExternal(entrada);
                     c.anadirDOM(p.getNombre(), String.valueOf(p.getEdad()), ruta);
                }
                catch(EOFException e){
                     finFichero = true;
                }
          }while(!finFichero);
     }
}

ARCHIVO MAIN.JAVA

import java.io.*;

public class Main {

     public static void main(String[] args) throws IOException, ClassNotFoundException{

          // Propiedades
          Acciones a = new Acciones();
          ConfigurarXML x = new ConfigurarXML();
         
          // Código para probar
          //a.escribirDat();
          a.cargarDatEnXML("personas.xml");
          System.out.println(x.leerXML("personas.xml"));
     }
}

2. Utiliza SAX para visualizar el contenido del fichero del apartado b) del ejercicio anterior.

ARCHIVO SAXREADER.JAVA

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.omg.Messaging.SyncScopeHelper;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class SAXReader extends DefaultHandler{

     public void leerXML(String ruta){
          try{
                // Obtengo y configuro el parseador SAX
                SAXParserFactory factory = SAXParserFactory.newInstance();
               
                // Obtengo el objeto del SAX parser
                SAXParser sParser = factory.newSAXParser();
               
                // Manejador por defecto. Los tres métodos se escriben dentro de él
                DefaultHandler manejador = new DefaultHandler(){
                     String nombreTag = "close";
                     String edadTag = "close";
                    
                     // Abro los elementos para capturar los datos contenidos
                     public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException{
                          System.out.println("<"+qName+">");
                         
                     } // fin función startElement
                    
                     // Imprime los datos contenidos entre < y >
                     public void characters(char ch[], int start, int length) throws SAXException{
                          String contenido = new String(ch, start, length).trim();
                          if (contenido.length() > 0)
                               System.out.println(contenido);
                     } // Fin función caracteres
                    
                     // Cierro los elementos para dejar de capturar datos
                     public void endElement(String uri, String localName, String qName) throws SAXException{
                          System.out.println("</"+qName+">");
                     } // Fin función endElement
                    
                }; // Fin DefaultHandler
               
                sParser.parse(ruta, manejador);
          }
          catch(Exception e){
                e.printStackTrace();
          }
     }
    
}

ARCHIVO MAIN.JAVA

import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.*;
import org.xml.sax.helpers.XMLReaderFactory;

public class Main {

     public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {

          SAXReader gestor = new SAXReader();
          gestor.leerXML("personas.xml");
     }

}

3.
a) Realiza un programa Java que cree un fichero binario para guardar datos (objetos) de departamentos (departamentos.dat). Los datos para cada departamento son:
- Numdepartamento: entero
- Nombre: String
- Localidad: String
Introduce varios departamentos
b) A partir del fichero departamentos.dat anterior, crea un fichero XML usando la librería XStream.
c) Crea una plantilla XSL para dar una presentación al fichero XML generado en el apartado b) y realiza un programa Java para transformarlo en HTML.

4. Realiza los dos últimos apartados del primer ejercicio pero utilizando Xstream.

ARCHIVO PERSONA.JAVA

import java.io.*;

public class Persona implements Serializable{

     // Propiedades
     private String nombre;
     private int edad;
    
     // Constructor
     public Persona(){}
     public Persona(String nombre, int edad){
          this.nombre = nombre;
          this.edad = edad;
     }
    
     // Métodos
     public void setNombre(String nombre){
          this.nombre = nombre;
     }
    
     public void setEdad(int edad){
          this.edad = edad;
     }
    
     public String getNombre(){
          return nombre;
     }
    
     public int getEdad(){
          return edad;
     }
    
     public String toString(){
          String resultado = "\t<PERSONA>\n" + "\t\t<NOMBRE>" + nombre + "</NOMBRE>\n" + "\t\t<EDAD>" + edad + "</EDAD>\n" + "\t</PERSONA>";
          return resultado;
     }
}

ARCHIVO ACCIONES.JAVA

import java.io.*;
import java.util.*;

import com.thoughtworks.xstream.XStream;

public class Acciones {

     // Propiedades
     private Persona p = new Persona();
    
     // Métodos
     /* Generar archivo para prueba
     public void escribirDat(String ruta) throws IOException, ClassNotFoundException{
          File depto = new File(ruta);
          ObjectOutputStream salida = new ObjectOutputStream(new FileOutputStream(ruta, true));
          Persona p1 = new Persona("Inazio", 23);
          salida.writeObject(p1);
          Persona p2 = new Persona("Claver", 24);
          salida.writeObject(p2);
          Persona p3 = new Persona("Paules", 25);
          salida.writeObject(p3);
          salida.close();
         
          System.out.println("Fichero guardado correctamente");
     }*/
    
     public void datToXML(String rutaDAT, String rutaXML){
          try{
                boolean finFichero = false;
                ObjectInputStream entrada = new ObjectInputStream(new FileInputStream(rutaDAT));
                Vector<Persona> listado = new Vector<Persona>();
               
                do{
                     try{
                          p = (Persona)entrada.readObject();
                          listado.add(p);
                     }
                     catch(EOFException e){
                          finFichero = true;
                     }
                }while(!finFichero);
               
                entrada.close();
               
                XStream xs = new XStream();
                xs.alias("GENTE", Vector.class);
                xs.alias("PERSONA", Persona.class);
                xs.toXML(listado, new FileOutputStream(new File(rutaXML)));
          }
          catch(ClassNotFoundException e){
                e.printStackTrace();
          }
          catch(FileNotFoundException e){
                e.printStackTrace();
          }
          catch(Exception e){
                e.printStackTrace();
          }
     }
    
     public void verXML(String ruta){
          XStream xs = new XStream();
          xs.alias("GENTE", Vector.class);
          xs.alias("PERSONA", Persona.class);
         
          Vector<Persona> listado = (Vector<Persona>)xs.fromXML(new File(ruta));
          Iterator<Persona> iterator = listado.listIterator();
         
          System.out.println("<GENTE>");
          while(iterator.hasNext()){
                System.out.println(((Persona)iterator.next()).toString());
          }
          System.out.println("</GENTE>");
     }
}

ARCHIVO MAIN.JAVA

import java.io.IOException;

public class Main {

     public static void main(String[] args) {
         
          Acciones a = new Acciones();
         
          /*Generar .dat para prueba
           * try{
                a.escribirDat("personas.dat");
          }
          catch(ClassNotFoundException e){
                e.printStackTrace();
          }
          catch(IOException e){
                e.printStackTrace();
          }*/
         
          a.datToXML("personas.dat", "personas.xml");
          a.verXML("personas.xml");
     }
}

5. Realiza los dos últimos apartados del primer ejercicio pero utilizando JDOM.

ARCHIVO PERSONA.JAVA

import java.io.*;

public class Persona implements Externalizable{

     // Propiedades
     private String nombre;
     private int edad;
    
     // Constructor
     public Persona(){}
    
     // Métodos
     public void setNombre(String nombre){
          this.nombre = nombre;
     }
    
     public void setEdad(int edad){
          this.edad = edad;
     }
    
     public String getNombre(){
          return nombre;
     }
    
     public int getEdad(){
          return edad;
     }
    
     public void writeExternal(ObjectOutput out) throws IOException{
          out.writeObject(nombre);
          out.writeObject(edad);
     }
    
     public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{
          nombre = (String)in.readObject();
          edad = (int)in.readObject();
     }
}

ARCHIVO JDOMTOXML.JAVA

import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.List;

import org.jdom2.*;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;

public class JDOMtoXML {

     public void generarXML(String nombreDAT, String nombreXML) throws IOException, ClassNotFoundException{
          boolean finFichero = false;
          Persona p = new Persona();
          ObjectInputStream entrada = new ObjectInputStream(new FileInputStream(nombreDAT));
          Element raiz = new Element("GENTE");
          Document doc = new Document();
         
          doc.setRootElement(raiz);
          do{
                try{
                     p.readExternal(entrada);
                     Element gente = new Element("PERSONA");
                     gente.addContent(new Element("NOMBRE").setText(p.getNombre()));
                     gente.addContent(new Element("EDAD").setText(String.valueOf(p.getEdad())));
                     doc.getRootElement().addContent(gente);
                }
                catch(EOFException e){
                     finFichero = true;
                }
          }while(!finFichero); // Dejo de recorrer el fichero .dat
         
          XMLOutputter x = new XMLOutputter();
          x.setFormat(Format.getPrettyFormat());
          x.output(doc, new FileWriter(nombreXML));
          System.out.println("Fichero generado correctamente");
     }
    
     public void leerXML(String ruta){
          SAXBuilder b = new SAXBuilder();
          File x = new File(ruta);
         
          try{
                // Creo el document
                Document d = (Document)b.build(x);
               
                // Leo la raíz
                Element raiz = d.getRootElement();
               
                // Obtengo listado de los hijos
                List listaHijos = raiz.getChildren("PERSONA");
               
                System.out.println("NOMBRE\t\tEDAD" );
                System.out.println("---------------------");
                for(int i = 0; i < listaHijos.size(); i++){
                     // Obtengo el elemento persona
                     Element persona = (Element)listaHijos.get(i);
                     String nombre = persona.getChildTextTrim("NOMBRE");
                     String edad = persona.getChildTextTrim("EDAD");
                    
                     System.out.println(nombre + "\t\t" + edad);                  
                }
          }
          catch(IOException e){
                e.printStackTrace();
          }
          catch(JDOMException e){
                e.printStackTrace();
          }
     }
}

ARCHIVO MAIN.JAVA

import java.io.IOException;
    
public class main {
     public static void main(String[] args) {
          JDOMtoXML j = new JDOMtoXML();
               
          try{
                j.generarXML("personas.dat", "personas.xml");
               j.leerXML("personas.xml");
          }
          catch(IOException e){
                e.printStackTrace();
          }
          catch(ClassNotFoundException e){
               e.printStackTrace();
          }
     }

}