Java tutorial
/** * Copyright 2008 Vctor Enrique Tamames, * Universidad de Valladolid, Espaa. * * This file is part of DelphSim. * * DelphSim is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or any later version. * * DelphSim is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * DelphSim. If not, see <http://www.gnu.org/licenses/>. */ /** * DelphSim (Delphos Simulator), simulador de epidemias desarrollado como * Proyecto Fin de Carrera de Ingeniera Informtica para la Escuela Tcnica * Superior de Ingeniera Informtica de la Universidad de Valladolid. */ package delphsim.model; import delphsim.util.*; import delphsim.util.random.*; import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.Vector; import java.util.HashSet; import javax.swing.DefaultListModel; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; import org.dom4j.tree.DefaultElement; import org.nfunk.jep.FunctionTable; import org.nfunk.jep.JEP; import org.nfunk.jep.function.*; import org.xml.sax.SAXException; /** * Clase representa la epidemia que se est modelando y se va a simular. * Contiene referencias a todos los elementos que la componen: parmetros, * procesos, poblacin, compartimentos generados, palabras reservadas, etc. * Tambin se encarga de cargar/guardar su informacin desde/a archivos XML. * @author Vctor E. Tamames Gmez */ public class Epidemia implements Cloneable { /** * Tiempo mximo de simulacin. */ private float tiempoSimulacion = 0; /** * Unidad de tiempo en la que se ha definido el modelo. */ private String unidadTiempo; /** * Conjunto de parmetros definidos para este modelo. */ private Parametro[] parametros = new Parametro[0]; /** * Conjunto de procesos definidos para este modelo. */ private Proceso[] procesos = new Proceso[0]; /** * Poblacin modelada para esta epidemia. */ private Poblacion poblacion; /** * Conjunto de compartimentos entre los que se distribuye la poblacin. */ private Compartimento[] compartimentos = new Compartimento[0]; /** * Conjunto de palabras clave o 'atajos' que permiten al usuario hacer * referencia a varios compartimentos al mismo tiempo. */ private Atajo[] atajos = new Atajo[0]; /** * Conjunto de resultados a obtener al trmino de una simulacin. */ private Resultado[] resultados = new Resultado[0]; /** * Palabras reservadas: contiene los nombres de los parmetros, de los * procesos y de las categoras, los cuales no pueden repetirse. */ private HashSet palabrasReservadas = new HashSet(); /** * Los nombres de los atajos para poder crearlos. */ private Vector palabrasAtajos = new Vector(); /** * Constructor de la clase. Crea un nuevo objeto y reserva por defecto las * funciones estndar disponibles. */ public Epidemia() { // Crear un nuevo JEP de DelphSim y reservar palabras JEP jep = Epidemia.CrearDelphSimJEP(); FunctionTable ft = jep.getFunctionTable(); for (Object e : ft.keySet()) { this.palabrasReservadas.add(e.toString()); } } /** * Mtodo que permite cambiar el tiempo de simulacin de la epidemia. * @param tiempoSimulacionEpi El nuevo tiempo de simulacin. */ public void setTiempoSimulacion(float tiempoSimulacionEpi) { this.tiempoSimulacion = tiempoSimulacionEpi; } /** * Mtodo que permite cambiar el tiempo de simulacin, transformndolo a las * unidades indicadas como parmetro. * @param tiempoSimulacionEpi Cunto tiempo debe simularse la epidemia. * @param unidadTiempo La unidad de tiempo en que se da el otro parmetro. * Es un nmero de 0 a 7 para Segundos, Minutos, Horas, * Das, Semanas, Meses o Aos en ese orden. */ public void setTiempoSimulacion(float tiempoSimulacionEpi, int unidadTiempo) { if (this.unidadTiempo.equals("Segundos")) { switch (unidadTiempo) { case 0: this.tiempoSimulacion = tiempoSimulacionEpi; break; case 1: this.tiempoSimulacion = tiempoSimulacionEpi * 60; break; case 2: this.tiempoSimulacion = tiempoSimulacionEpi * 3600; break; case 3: this.tiempoSimulacion = tiempoSimulacionEpi * 86400; break; case 4: this.tiempoSimulacion = tiempoSimulacionEpi * 604800; break; case 5: this.tiempoSimulacion = tiempoSimulacionEpi * 2592000; break; case 6: this.tiempoSimulacion = tiempoSimulacionEpi * 31536000; break; default: return; } } else if (this.unidadTiempo.equals("Minutos")) { switch (unidadTiempo) { case 0: this.tiempoSimulacion = tiempoSimulacionEpi / 60; break; case 1: this.tiempoSimulacion = tiempoSimulacionEpi; break; case 2: this.tiempoSimulacion = tiempoSimulacionEpi * 60; break; case 3: this.tiempoSimulacion = tiempoSimulacionEpi * 1440; break; case 4: this.tiempoSimulacion = tiempoSimulacionEpi * 10080; break; case 5: this.tiempoSimulacion = tiempoSimulacionEpi * 43200; break; case 6: this.tiempoSimulacion = tiempoSimulacionEpi * 525600; break; default: return; } } else if (this.unidadTiempo.equals("Horas")) { switch (unidadTiempo) { case 0: this.tiempoSimulacion = tiempoSimulacionEpi / 360; break; case 1: this.tiempoSimulacion = tiempoSimulacionEpi / 60; break; case 2: this.tiempoSimulacion = tiempoSimulacionEpi; break; case 3: this.tiempoSimulacion = tiempoSimulacionEpi * 24; break; case 4: this.tiempoSimulacion = tiempoSimulacionEpi * 168; break; case 5: this.tiempoSimulacion = tiempoSimulacionEpi * 720; break; case 6: this.tiempoSimulacion = tiempoSimulacionEpi * 8760; break; default: return; } } else if (this.unidadTiempo.equals("Das")) { switch (unidadTiempo) { case 0: this.tiempoSimulacion = tiempoSimulacionEpi / 86400; break; case 1: this.tiempoSimulacion = tiempoSimulacionEpi / 1440; break; case 2: this.tiempoSimulacion = tiempoSimulacionEpi / 24; break; case 3: this.tiempoSimulacion = tiempoSimulacionEpi; break; case 4: this.tiempoSimulacion = tiempoSimulacionEpi * 7; break; case 5: this.tiempoSimulacion = tiempoSimulacionEpi * 30; break; case 6: this.tiempoSimulacion = tiempoSimulacionEpi * 365; break; default: return; } } else if (this.unidadTiempo.equals("Semanas")) { switch (unidadTiempo) { case 0: this.tiempoSimulacion = tiempoSimulacionEpi / 604800; break; case 1: this.tiempoSimulacion = tiempoSimulacionEpi / 10080; break; case 2: this.tiempoSimulacion = tiempoSimulacionEpi / 168; break; case 3: this.tiempoSimulacion = tiempoSimulacionEpi / 7; break; case 4: this.tiempoSimulacion = tiempoSimulacionEpi; break; case 5: this.tiempoSimulacion = (tiempoSimulacionEpi / 7) * 30; break; case 6: this.tiempoSimulacion = (tiempoSimulacionEpi / 7) * 365; break; default: return; } } else if (this.unidadTiempo.equals("Meses")) { switch (unidadTiempo) { case 0: this.tiempoSimulacion = tiempoSimulacionEpi / 2592000; break; case 1: this.tiempoSimulacion = tiempoSimulacionEpi / 43200; break; case 2: this.tiempoSimulacion = tiempoSimulacionEpi / 720; break; case 3: this.tiempoSimulacion = tiempoSimulacionEpi / 30; break; case 4: this.tiempoSimulacion = (tiempoSimulacionEpi / 30) * 7; break; case 5: this.tiempoSimulacion = tiempoSimulacionEpi; break; case 6: this.tiempoSimulacion = (tiempoSimulacionEpi / 30) * 365; break; default: return; } } else if (this.unidadTiempo.equals("Aos")) { switch (unidadTiempo) { case 0: this.tiempoSimulacion = tiempoSimulacionEpi / 31536000; break; case 1: this.tiempoSimulacion = tiempoSimulacionEpi / 525600; break; case 2: this.tiempoSimulacion = tiempoSimulacionEpi / 8760; break; case 3: this.tiempoSimulacion = tiempoSimulacionEpi / 365; break; case 4: this.tiempoSimulacion = (tiempoSimulacionEpi / 365) * 7; break; case 5: this.tiempoSimulacion = (tiempoSimulacionEpi / 365) * 30; break; case 6: this.tiempoSimulacion = tiempoSimulacionEpi; break; default: return; } } } /** * Mtodo que permite obtener el tiempo de simulacin de la epidemia. * @return El tiempo total de simulacin. */ public float getTiempoSimulacion() { return this.tiempoSimulacion; } /** * Mtodo que permite cambiar la unidad de tiempo en que estn especificados * los elementos del modelo. * @param unidadTiempoEpi La nueva unidad de tiempo. */ public void setUnidadTiempo(String unidadTiempoEpi) { this.unidadTiempo = unidadTiempoEpi; } /** * Mtodo que permite obtener la unidad de tiempo en que estn especificados * los elementos del modelo. * @return La unidad de tiempo en una cadena de texto. */ public String getUnidadTiempo() { return this.unidadTiempo; } /** * Mtodo para cambiar la poblacin de la epidemia. * @param poblacionEpi La nueva poblacin. */ public void setPoblacion(Poblacion poblacionEpi) { this.poblacion = poblacionEpi; } /** * Mtodo para obtener la poblacin de la epidemia. * @return La poblacin de la epidemia. */ public Poblacion getPoblacion() { return this.poblacion; } /** * Mtodo para cambiar los compartimentos de la poblacin. * @param compartimentosEpi El nuevo conjunto de compartimentos. */ public void setCompartimentos(Compartimento[] compartimentosEpi) { this.compartimentos = compartimentosEpi; } /** * Mtodo para cambiar un compartimento de la poblacin. * @param compartimentosEpi El nuevo compartimento. * @param indice El ndice del compartimento a sustituir por el nuevo. */ public void setCompartimento(Compartimento compartimentosEpi, int indice) { this.compartimentos[indice] = compartimentosEpi; } /** * Mtodo para obtener el conjunto de compartimentos de la poblacin. * @return El conjunto de compartimentos de la poblacin. */ public Compartimento[] getCompartimentos() { return this.compartimentos; } /** * Mtodo para obtener un compartimento. * @param indice El ndice del compartimento. * @return El compartimento. */ public Compartimento getCompartimento(int indice) { return this.compartimentos[indice]; } /** * Mtodo para obtener un compartimento. * @param nombre El nombre del compartimento. * @return El compartimento. */ public Compartimento getCompartimento(String nombre) { for (int i = 0; i < this.compartimentos.length; i++) { if (this.compartimentos[i].getNombre().equals(nombre)) return this.compartimentos[i]; } return null; } /** * Mtodo para cambiar el conjunto de parmetros del modelo. * @param parametrosEpi El nuevo conjunto de parmetros. */ public void setParametros(Parametro[] parametrosEpi) { this.parametros = parametrosEpi; } /** * Mtodo para cambiar un parmetro del modelo. * @param parametroEpi El nuevo parmetro. * @param indice El ndice del parmetro a reemplazar. */ public void setParametro(Parametro parametroEpi, int indice) { this.parametros[indice] = parametroEpi; } /** * Mtodo para obtener el conjunto de parmetros del modelo. * @return El conjunto de parmetros del modelo. */ public Parametro[] getParametros() { return this.parametros; } /** * Mtodo para obtener un parmetro del modelo. * @param indice El ndice del parmetro a obtener. * @return El parmetro. */ public Parametro getParametro(int indice) { return this.parametros[indice]; } /** * Mtodo para obtener un parmetro del modelo. * @param nombre El nombre del parmetro a obtener. * @return El parmetro. */ public Parametro getParametro(String nombre) { for (int i = 0; i < this.parametros.length; i++) { if (this.parametros[i].getNombre().equals(nombre)) return this.parametros[i]; } return null; } /** * Aade un parmetro nuevo a la lista actual de parmetros. * @param param El parmetro a aadir. */ public void anadirParametro(Parametro param) { Parametro[] nuevaLista = new Parametro[this.parametros.length + 1]; for (int i = 0; i < this.parametros.length; i++) { nuevaLista[i] = this.parametros[i]; } nuevaLista[this.parametros.length] = param; this.parametros = nuevaLista; } /** * Elimina el parmetro indicado por el ndice de la lista de parmetros. * @param indice La posicin en la que se encuentra el parmetro. */ public void eliminarParametro(int indice) { // Rehacer la lista, pero sin el parmetro eliminado String nombreParEliminado = this.parametros[indice].getNombre(); Parametro[] nuevosParametros = new Parametro[this.parametros.length - 1]; for (int i = 0; i < this.parametros.length; i++) { if (i < indice) { nuevosParametros[i] = this.parametros[i]; } else if (i > indice) { nuevosParametros[i - 1] = this.parametros[i]; } } // Este parametro podra depender de otros, eliminar esas dependencias for (Parametro par : nuevosParametros) { par.eliminarParametroVinculado(nombreParEliminado); } // El nombre de este parmetro deja de estar reservado this.palabrasReservadas.remove(nombreParEliminado); // Asignar la nueva lista this.parametros = nuevosParametros; } /** * Intercambia el parmetro de la posicin posInicial con el de la posicin * posFinal. * @param posInicial Posicin origen del parmetro. * @param posFinal Posicin destino del parmetro. */ public void moverParametro(int posInicial, int posFinal) { Parametro origen = this.getParametro(posInicial); Parametro destino = this.getParametro(posFinal); this.parametros[posInicial] = destino; this.parametros[posFinal] = origen; } /** * Mtodo para cambiar el conjunto de procesos del modelo. * @param procesosEpi El nuevo conjunto de procesos. */ public void setProcesos(Proceso[] procesosEpi) { this.procesos = procesosEpi; } /** * Mtodo para cambiar un proceso del modelo. * @param procesoEpi El nuevo proceso. * @param indice El ndice del proceso a reemplazar. */ public void setProceso(Proceso procesoEpi, int indice) { this.procesos[indice] = procesoEpi; } /** * Mtodo para obtener el conjunto de procesos del modelo. * @return El conjunto de procesos. */ public Proceso[] getProcesos() { return this.procesos; } /** * Mtodo para obtener un proceso del modelo. * @param indice El ndice del proceso a obtener. * @return El proceso. */ public Proceso getProceso(int indice) { return this.procesos[indice]; } /** * Mtodo para obtener un proceso del modelo. * @param nombre El nombre del proceso a obtener. * @return El proceso. */ public Proceso getProceso(String nombre) { for (int i = 0; i < this.procesos.length; i++) { if (this.procesos[i].getNombre().equals(nombre)) return this.procesos[i]; } return null; } /** * Aade un proceso nuevo a la lista actual de procesos. * @param proc El proceso a aadir. */ public void anadirProceso(Proceso proc) { Proceso[] nuevaLista = new Proceso[this.procesos.length + 1]; for (int i = 0; i < this.procesos.length; i++) { nuevaLista[i] = this.procesos[i]; } nuevaLista[this.procesos.length] = proc; this.procesos = nuevaLista; } /** * Elimina el proceso indicado por el ndice de la lista de procesos. * @param indice La posicin en la que se encuentra el proceso. */ public void eliminarProceso(int indice) { // Rehacer la lista, pero sin el proceso eliminado String nombreProcEliminado = this.procesos[indice].getNombre(); Proceso[] nuevosProcesos = new Proceso[this.procesos.length - 1]; for (int i = 0; i < this.procesos.length; i++) { if (i < indice) { nuevosProcesos[i] = this.procesos[i]; } else if (i > indice) { nuevosProcesos[i - 1] = this.procesos[i]; } } // Este proceso podra depender de otros parametros, procesos o // compartimentos; eliminar esas dependencias for (Parametro par : this.parametros) { par.eliminarProcesoVinculado(nombreProcEliminado); } for (Proceso proc : this.procesos) { proc.eliminarProcesoVinculado(nombreProcEliminado); } for (Compartimento comp : this.compartimentos) { comp.eliminarProcesoVinculado(nombreProcEliminado); } // El nombre de este proceso deja de estar reservado this.palabrasReservadas.remove(nombreProcEliminado); // Asignar la nueva lista this.procesos = nuevosProcesos; } /** * Intercambia el proceso de la posicin posInicial con el de la posicin * posFinal. * @param posInicial Posicin origen del proceso. * @param posFinal Posicin destino del proceso. */ public void moverProceso(int posInicial, int posFinal) { Proceso origen = this.getProceso(posInicial); Proceso destino = this.getProceso(posFinal); this.procesos[posInicial] = destino; this.procesos[posFinal] = origen; } /** * Mtodo para cambiar el conjunto de atajos del modelo. * @param atajosEpi El nuevo conjunto de atajos. */ public void setAtajos(Atajo[] atajosEpi) { this.atajos = atajosEpi; } /** * Mtodo para cambiar un atajo del modelo. * @param ataj El nuevo atajo. * @param indice El ndice del atajo a reemplazar. */ public void setAtajo(Atajo ataj, int indice) { this.atajos[indice] = ataj; } /** * Mtodo para obtener el conjunto de atajos del modelo. * @return El conjunto de atajos. */ public Atajo[] getAtajos() { return this.atajos; } /** * Mtodo para obtener un atajo del modelo. * @param indice El ndice del atajo a obtener. * @return El atajo. */ public Atajo getAtajo(int indice) { return this.atajos[indice]; } /** * Mtodo para obtener un atajo del modelo. * @param nombre El nombre del atajo a obtener. * @return El atajo. */ public Atajo getAtajo(String nombre) { for (int i = 0; i < this.atajos.length; i++) { if (this.atajos[i].getNombre().equals(nombre)) return this.atajos[i]; } return null; } /** * Mtodo para cambiar el conjunto de resultados del modelo. * @param res El nuevo conjunto de resultados. */ public void setResultados(Resultado[] res) { if (resultados != null) { for (int i = 0; i < this.resultados.length; i++) { this.resultados[i].eliminarFunciones(); } } this.resultados = res; } /** * Mtodo para cambiar un resultado del modelo. * @param res El nuevo resultado. * @param indice El ndice del resultado a reemplazar. */ public void setResultado(Resultado res, int indice) { if (this.resultados[indice] != null) { this.resultados[indice].eliminarFunciones(); } this.resultados[indice] = res; } /** * Mtodo para obtener el conjunto de resultados del modelo. * @return El conjunto de resultados. */ public Resultado[] getResultados() { return this.resultados; } /** * Mtodo para obtener un resultado del modelo. * @param indice El ndice del resultado a obtener. * @return El resultado. */ public Resultado getResultado(int indice) { return this.resultados[indice]; } /** * Aade un resultado nuevo a la lista actual de resultados. * @param res El resultado a aadir. */ public void anadirResultado(Resultado res) { Resultado[] nuevaLista = new Resultado[this.resultados.length + 1]; for (int i = 0; i < this.resultados.length; i++) { nuevaLista[i] = this.resultados[i]; } nuevaLista[this.resultados.length] = res; this.resultados = nuevaLista; } /** * Elimina el resultado indicado por el ndice de la lista de resultados. * @param indice La posicin en la que se encuentra el resultado. */ public void eliminarResultado(int indice) { // Rehacer la lista, pero sin el resultado eliminado Resultado[] nuevosResultados = new Resultado[this.resultados.length - 1]; for (int i = 0; i < this.resultados.length; i++) { if (i < indice) { nuevosResultados[i] = this.resultados[i]; } else if (i > indice) { nuevosResultados[i - 1] = this.resultados[i]; } } // Asignar la nueva lista this.resultados = nuevosResultados; } /** * Vaca la lista de resultados. */ public void eliminarResultados() { if (this.resultados != null) { for (int i = 0; i < this.resultados.length; i++) { this.resultados[i].eliminarFunciones(); } } File f = new File(new File(System.getProperty("java.class.path")).getParent() + File.separator + "temp" + File.separator + "tiempo_.temp"); if (f.exists()) { if (!f.delete()) { f.deleteOnExit(); } } this.resultados = new Resultado[0]; } /** * Mtodo para cambiar el conjunto de palabras reservadas. * @param pRes El nuevo conjunto de palabras reservadas. */ public void setPalabrasReservadas(HashSet pRes) { this.palabrasReservadas = pRes; } /** * Mtodo para obtener el conjunto de palabras reservadas. * @return El conjunto de palabras reservadas. */ public HashSet getPalabrasReservadas() { return this.palabrasReservadas; } /** * Mtodo para cambiar el conjunto de nombres de atajos. * @param pAjs El nuevo conjunto de nombres de atajos. */ public void setPalabrasAtajos(Vector pAjs) { this.palabrasAtajos = pAjs; } /** * Mtodo para obtener el conjunto de nombres de atajos. * @return El conjunto de nombres de atajos. */ public Vector getPalabrasAtajos() { return this.palabrasAtajos; } /** * Comprueba si el elemento indicado ya est definido, bien sea como * parmetro, bien como proceso, bien como compartimento, o como atajo. * @param elemento El elemento a comprobar, de tipo Parametro, Proceso, * Compartimento o String (el nombre directamente). * @return Si ya est definido, el tipo del objeto existente. Si no, null. */ public Class estaDefinido(Object elemento) { String nombre = ""; if (elemento.getClass() == Parametro.class) { nombre = ((Parametro) elemento).getNombre(); } else if (elemento.getClass() == Proceso.class) { nombre = ((Proceso) elemento).getNombre(); } else if (elemento.getClass() == Compartimento.class) { nombre = ((Compartimento) elemento).getNombre(); } else { nombre = elemento.toString(); } for (int i = 0; i < this.parametros.length; i++) { if (this.parametros[i].getNombre().equals(nombre)) { return Parametro.class; } } for (int i = 0; i < this.procesos.length; i++) { if (this.procesos[i].getNombre().equals(nombre)) { return Proceso.class; } } for (int i = 0; i < this.compartimentos.length; i++) { if (this.compartimentos[i].getNombre().equals(nombre)) { return Compartimento.class; } } if (this.palabrasAtajos.contains(nombre)) { return Atajo.class; } JEP jep = Epidemia.CrearDelphSimJEP(); FunctionTable functionTable = jep.getFunctionTable(); if (functionTable.containsKey(elemento)) { return PostfixMathCommand.class; } return null; } /** * Analiza sintcticamente el archivo XML pasado como parmetro y devuelve * un objeto tipo rbol. * @param archivoOrigen El archivo XML a analizar. * @return Un objeto tipo rbol para poder trabajar con la informacin. * @throws org.dom4j.DocumentException Si hay algn problema al leer el archivo. */ private Document analizar(File archivoOrigen) throws DocumentException { SAXReader reader = new SAXReader(); Document document = reader.read(archivoOrigen); return document; } /** * Abre un archivo XML y, si es correcto y vlido, carga su informacin en * esta epidemia. * @param XMLSchema Ruta relativa al archivo .xsd contra el que hay que * validar el fichero que se quiere abrir. * @param archivoOrigen El fichero que se quiere abrir. * @return Una cadena con los errores detectados. Vaca si no hay ninguno. * @throws org.dom4j.DocumentException Si hay algn problema al analizar el archivo. * @throws org.xml.sax.SAXException Si hay algn problema al validar el archivo. * @throws java.io.IOException Si hay algn problema al leer el archivo. */ public String abrirXML(String XMLSchema, File archivoOrigen) throws DocumentException, SAXException, IOException { // Comprobar que el archivo se ajusta al esquema XML de DelphSim SchemaValidator validadorEsquemas = new SchemaValidator(); validadorEsquemas.setXMLSchemaURL(new File(System.getProperty("java.class.path")).getParent() + XMLSchema); String errores = validadorEsquemas.validar(archivoOrigen); if (errores.equals("")) { // Abrir el archivo XML de la ruta especificada y coger el elemento "epidemia" (raz) Document archivoXML = this.analizar(archivoOrigen); Element elementoEpidemia = archivoXML.getRootElement(); if (elementoEpidemia.attributeValue("unidadTiempo") != null) { this.unidadTiempo = elementoEpidemia.attributeValue("unidadTiempo"); } // Iterar para recuperar todos los elementos "parmetro" y crear los objetos Vector vectorParametros = new Vector(); this.parametros = new Parametro[elementoEpidemia.elements("parametro").size()]; int indice = 0; for (Iterator i = elementoEpidemia.elementIterator("parametro"); i.hasNext();) { Element elementoParametro = (Element) i.next(); this.parametros[indice] = new Parametro(); this.parametros[indice].cargarDesdeXML(elementoParametro); vectorParametros.add(this.parametros[indice].getNombre()); this.palabrasReservadas.add(this.parametros[indice].getNombre()); indice++; } // Iterar para recuperar todos los elementos "proceso" y crear los objetos Vector vectorProcesos = new Vector(); this.procesos = new Proceso[elementoEpidemia.elements("proceso").size()]; indice = 0; for (Iterator i = elementoEpidemia.elementIterator("proceso"); i.hasNext();) { Element elementoProceso = (Element) i.next(); this.procesos[indice] = new Proceso(); this.procesos[indice].cargarDesdeXML(elementoProceso); vectorProcesos.add(this.procesos[indice].getNombre()); this.palabrasReservadas.add(this.procesos[indice].getNombre()); indice++; } // Comprobar que, dentro de los parmetros, parametrosVinculados y // procesosVinculados usen nombres definidos y adems que // parametrosVinculados estn en el orden apropiado. for (int i = 0; i < this.parametros.length; i++) { String nombrePar = this.parametros[i].getNombre(); String[] parVinc = this.parametros[i].getParametrosVinculados(); String[] procVinc = this.parametros[i].getProcesosVinculados(); for (int j = 0; j < parVinc.length; j++) { int posicion = vectorParametros.indexOf(parVinc[j]); if (posicion == -1) { errores += String.format( "<Error> El parmetro '%s' se utiliza en la definicin del parmetro '%s', " + "pero ste ltimo no se ha definido realmente.\n\n", nombrePar, parVinc[j]); } else if (posicion == i) { errores += String.format("<Error> El parmetro '%s' no puede depender de s mismo.\n\n", nombrePar); } else if (posicion < i) { errores += String.format("<Advertencia> El parmetro '%s' depende del parmetro '%s', " + "por lo que debe definirse despus de l.\n\n", parVinc[j], nombrePar); } } for (int j = 0; j < procVinc.length; j++) { if (!vectorProcesos.contains(procVinc[j])) { errores += String.format( "<Error> El parmetro '%s' se utiliza en la definicin del proceso '%s', " + "pero ste ltimo no se ha definido realmente.\n\n", nombrePar, procVinc[j]); } } } // Comprobar que, dentro de los procesos, procesosVinculados usen // nombres definidos y estn en el orden apropiado. for (int i = 0; i < this.procesos.length; i++) { String nombreProc = this.procesos[i].getNombre(); String[] procVinc = this.procesos[i].getProcesosVinculados(); for (int j = 0; j < procVinc.length; j++) { int posicion = vectorProcesos.indexOf(procVinc[j]); if (posicion == -1) { errores += String.format( "<Error> El proceso '%s' se utiliza en la definicin del proceso '%s', " + "pero ste ltimo no se ha definido realmente.\n\n", nombreProc, procVinc[j]); } else if (posicion == i) { errores += String.format("<Error> El proceso '%s' no puede depender de s mismo.\n\n", nombreProc); } else if (posicion < i) { errores += String.format( "<Advertencia> El proceso '%s' depende del proceso '%s', " + "por lo que debe definirse despus de l.\n\n", procVinc[j], nombreProc); } } } // Recuperar el elemento "poblacion" y crear el objeto correspondiente Element elementoPoblacion = elementoEpidemia.element("poblacion"); this.poblacion = new Poblacion(); this.poblacion.cargarDesdeXML(elementoPoblacion); // Iterar para recuperar todos los elementos "compartimento" y crear los objetos // Comprobar que el nmero, nombre y orden de los compartimentos corresponda con las categoras this.compartimentos = new Compartimento[elementoEpidemia.elements("compartimento").size()]; String[] segunDivisiones = this.combinarCategorias(null); if (segunDivisiones.length != this.compartimentos.length) { errores += "<Error> Los compartimentos definidos en el archivo abierto no se corresponden " + "con la verdadera combinacin de las distintas categoras definidas."; return errores; } indice = 0; for (Iterator i = elementoEpidemia.elementIterator("compartimento"); i.hasNext();) { Element elementoCompartimento = (Element) i.next(); this.compartimentos[indice] = new Compartimento(); this.compartimentos[indice].cargarDesdeXML(elementoCompartimento); if (!this.compartimentos[indice].getNombre().equals(segunDivisiones[indice])) { errores += "<Error> Los compartimentos definidos en el archivo abierto no se corresponden " + "con la verdadera combinacin de las distintas categoras definidas."; return errores; } this.palabrasReservadas.add(this.compartimentos[indice].getNombre()); indice++; } // Generar los atajos correspondientes a los compartimentos cargados this.generarAtajos(); } // Devolver los errores producidos, cadena vaca si no ha habido return errores; } /** * Guarda la informacin de esta epidemia en el archivo pasado como * parmetro, siguiendo el esquema del .xsd de la aplicacin. * @param archivoDestino El archivo destino donde se guardar el modelo. * @throws java.io.IOException Si hay problemas al escribir en disco. * @throws org.dom4j.DocumentException Si hay problemas al crear el objeto de tipo rbol. * @throws java.lang.Exception Si se produce algn otro problema. */ public void guardarXML(File archivoDestino) throws IOException, DocumentException, Exception { // Primero crear el documento dom4j con la informacin del modelo Document documento = DocumentHelper.createDocument(); // Elemento raz epidemia Element elementoEpidemia = new DefaultElement("epidemia"); documento.setRootElement(elementoEpidemia); elementoEpidemia.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); elementoEpidemia.addAttribute("xsi:noNamespaceSchemaLocation", "DelphSim1.18.xsd"); elementoEpidemia.addAttribute("unidadTiempo", this.unidadTiempo); // Elementos parmetros if (this.parametros != null) { for (Parametro param : this.parametros) { Element elementoParametro = param.volcarAXML(); elementoEpidemia.add(elementoParametro); } } // Elementos procesos if (this.procesos != null) { for (Proceso proc : this.procesos) { Element elementoProceso = proc.volcarAXML(); elementoEpidemia.add(elementoProceso); } } // Elemento poblacin Element elementoPoblacion = this.poblacion.volcarAXML(); elementoEpidemia.add(elementoPoblacion); // Elementos compartimentos for (Compartimento comp : this.compartimentos) { Element elementoCompartimento = comp.volcarAXML(); elementoEpidemia.add(elementoCompartimento); } // Luego crear el formato, stream y escritor de la salida OutputFormat formato = OutputFormat.createPrettyPrint(); formato.setEncoding("UTF-16"); formato.setIndent("\t"); formato.setNewLineAfterDeclaration(false); formato.setPadText(false); formato.setTrimText(true); formato.setXHTML(true); java.io.OutputStreamWriter salida = new java.io.OutputStreamWriter( new java.io.FileOutputStream(archivoDestino), "UTF-16"); XMLWriter escritor = new XMLWriter(salida, formato); // Y escribir escritor.write(documento); escritor.close(); } /** * Construye el modelo del JList de la interfaz en base a los compartimentos * de esta epidemia. * @return El modelo de la lista de los compartimentos. */ public DefaultListModel construirListaCompartimentos() { DefaultListModel listaCompartimentos = new DefaultListModel(); for (Compartimento comp : this.getCompartimentos()) { listaCompartimentos.addElement(comp.getNombre()); } return listaCompartimentos; } /** * Construye el modelo del JList de la interfaz en base a los parmetros * de esta epidemia. * @return El modelo de la lista de los parmetros. */ public DefaultListModel construirListaParametros() { DefaultListModel listaParametros = new DefaultListModel(); if (this.getParametros() != null) { for (Parametro par : this.getParametros()) { listaParametros.addElement(par.getNombre()); } } return listaParametros; } /** * Construye el modelo del JList de la interfaz en base a los procesos * de esta epidemia. * @return El modelo de la lista de los procesos. */ public DefaultListModel construirListaProcesos() { DefaultListModel listaProcesos = new DefaultListModel(); if (this.getProcesos() != null) { for (Proceso proc : this.getProcesos()) { listaProcesos.addElement(proc.getNombre()); } } return listaProcesos; } /** * Construye el modelo del JList de la interfaz en base a los resultados * de esta epidemia. * @return El modelo de la lista de los resultados. */ public DefaultListModel construirListaResultados() { DefaultListModel listaResultados = new DefaultListModel(); if (this.getResultados() != null) { for (Resultado res : this.getResultados()) { listaResultados.addElement(res.getTitulo()); } } return listaResultados; } /** * Mtodo que genera todas las combinaciones de categoras, una por cada * divisin, obteniendo todos los compartimentos posibles. * @param divisiones Parmetro opcional con las divisiones a combinar. Si * fuera <i>null</i>, se combinaran las categoras de la * epidemia que invoca este mtodo. * @return Un vector de cadenas de texto, cada elemento representa uno de * los compartimentos generados por combinacin. */ public String[] combinarCategorias(Division[] divisiones) { // Si divs es null, se usan las de la epidemia if (divisiones == null) { divisiones = this.getPoblacion().getDivisiones(); } // Clculo del nmero de secciones a generar por combinacin int numeroClasificaciones = 1; for (Division division : divisiones) { numeroClasificaciones *= division.getCategorias().length; } String clasificaciones[] = new String[numeroClasificaciones]; // Combinar una categora de cada divisin int repetirNVeces = numeroClasificaciones; int repetirMVeces = 1; Categoria[] categorias; for (int i = 0; i < divisiones.length; i++) { categorias = divisiones[i].getCategorias(); repetirNVeces = repetirNVeces / categorias.length; for (int j = 0; j < categorias.length; j++) { for (int l = 0; l < repetirMVeces; l++) { for (int k = 0; k < repetirNVeces; k++) { if (clasificaciones[l * (numeroClasificaciones / repetirMVeces) + repetirNVeces * j + k] == null) { clasificaciones[l * (numeroClasificaciones / repetirMVeces) + repetirNVeces * j + k] = categorias[j].getNombre(); } else { clasificaciones[l * (numeroClasificaciones / repetirMVeces) + repetirNVeces * j + k] += "_" + categorias[j].getNombre(); } } } } repetirMVeces = repetirMVeces * categorias.length; } return clasificaciones; } /** * Patrn 'factory' aplicado a la creacin de analizadores sintcticos * matemticos (JEP). Este mtodo crea una nueva instancia del objeto JEP, * iniciada con las funciones que estarn disponibles en la aplicacin. * Todas las instancias de JEP deben crearse con este mtodo. */ public static JEP CrearDelphSimJEP() { // Creamos un JEP vaco JEP jep = new JEP(); // Le aadimos las funciones predefinidas en la librera solicitadas jep.addFunction("sin", new Sine()); jep.addFunction("cos", new Cosine()); jep.addFunction("tan", new Tangent()); jep.addFunction("asin", new ArcSine()); jep.addFunction("acos", new ArcCosine()); jep.addFunction("atan", new ArcTangent()); jep.addFunction("atan2", new ArcTangent2()); jep.addFunction("sinh", new SineH()); jep.addFunction("cosh", new CosineH()); jep.addFunction("tanh", new TanH()); jep.addFunction("asinh", new ArcSineH()); jep.addFunction("acosh", new ArcCosineH()); jep.addFunction("atanh", new ArcTanH()); jep.addFunction("log", new Logarithm()); jep.addFunction("ln", new NaturalLogarithm()); jep.addFunction("exp", new Exp()); jep.addFunction("pow", new Power()); jep.addFunction("sqrt", new SquareRoot()); jep.addFunction("abs", new Abs()); jep.addFunction("mod", new Modulus()); jep.addFunction("sum", new Sum()); jep.addFunction("rand", new org.nfunk.jep.function.Random()); jep.addFunction("round", new Round()); jep.addFunction("floor", new Floor()); jep.addFunction("ceil", new Ceil()); // Distribuciones de probabilidad discretas jep.addFunction("Binomial", new JEPBinomial()); jep.addFunction("BinomialNegativa", new JEPBinomialNegativa()); jep.addFunction("Hipergeometrica", new JEPHipergeometrica()); jep.addFunction("Poisson", new JEPPoisson()); // Distribuciones de probabilidad continuas jep.addFunction("Beta", new JEPBeta()); jep.addFunction("JiCuadrado", new JEPJiCuadrado()); jep.addFunction("Exponencial", new JEPExponencial()); jep.addFunction("Gamma", new JEPGamma()); jep.addFunction("Normal", new JEPNormal()); jep.addFunction("TStudent", new JEPTStudent()); jep.addFunction("Uniforme", new JEPUniforme()); return jep; } /** * Mtodo recursivo que calcula los nombres identificativos de los atajos * en base a los compartimentos de esta epidemia. La recursividad comienza * con la cadena vaca, divisin cero. * @param cadena El nombre del atajo calculado hasta el momento. * @param divisionMeLlego Divisin por la que me llego aadiendo categoras * al atajo. */ private void calcularAtajos(String cadena, int divisionMeLlego) { // Desde la divisin por la que llegue hasta la ltima String nuevaCadena = ""; for (int i = divisionMeLlego; i < this.getPoblacion().getDivisiones().length; i++) { // Para cada categora de esa divisin for (int j = 0; j < this.getPoblacion().getDivisiones()[i].getCategorias().length; j++) { // Combino su nombre con la cadena pasada y se aade como atajo nuevaCadena = cadena + this.getPoblacion().getDivisiones()[i].getCategorias()[j].getNombre(); if (nuevaCadena.split("_").length < this.getPoblacion().getDivisiones().length) { if (!this.palabrasAtajos.contains(nuevaCadena)) { this.palabrasAtajos.add(nuevaCadena); } } // Como no es la ltima, separamos de la siguiente con un guin nuevaCadena += "_"; // Y llamamos recursivamente a esta funcin para cada divisin siguiente for (int k = i + 1; k < this.getPoblacion().getDivisiones().length; k++) { this.calcularAtajos(nuevaCadena, k); } } } } /** * Genera los objetos Atajo usando los nombres calculados previamente. * @see #calcularAtajos(java.lang.String, int) */ public void generarAtajos() { // Vaciamos el vector, lo recalculamos y creamos los objetos Atajo this.palabrasAtajos.clear(); this.calcularAtajos("", 0); this.atajos = new Atajo[this.palabrasAtajos.size()]; // Para cada uno de ellos, creamos un Atajo con su nombre y pasndole // los compartimentos para que sepa calcular su definicin for (int i = 0; i < this.palabrasAtajos.size(); i++) { this.atajos[i] = new Atajo(this.palabrasAtajos.get(i).toString(), this.getCompartimentos()); } } /** * Implementacin de la interfaz Cloneable. * @return Un clon idntico a este objeto. */ @Override public Epidemia clone() { int numPars = this.getParametros().length; int numProcs = this.getProcesos().length; int numComps = this.getCompartimentos().length; int numAtaj = this.getAtajos().length; int numResu = this.getResultados().length; Epidemia clon = new Epidemia(); clon.setUnidadTiempo(this.getUnidadTiempo()); clon.setTiempoSimulacion(this.getTiempoSimulacion()); clon.setPoblacion(this.getPoblacion().clone()); clon.setParametros(new Parametro[numPars]); for (int i = 0; i < numPars; i++) { clon.setParametro(this.getParametro(i).clone(), i); } clon.setProcesos(new Proceso[numProcs]); for (int i = 0; i < numProcs; i++) { clon.setProceso(this.getProceso(i).clone(), i); } clon.setCompartimentos(new Compartimento[numComps]); for (int i = 0; i < numComps; i++) { clon.setCompartimento(this.getCompartimento(i).clone(), i); } clon.setAtajos(new Atajo[numAtaj]); for (int i = 0; i < numAtaj; i++) { clon.setAtajo(this.getAtajo(i).clone(), i); } clon.setResultados(new Resultado[numResu]); for (int i = 0; i < numResu; i++) { clon.setResultado(this.getResultado(i).clone(), i); } clon.setPalabrasReservadas((HashSet) this.getPalabrasReservadas().clone()); clon.setPalabrasAtajos((Vector) this.getPalabrasAtajos().clone()); return clon; } }