Posts
- codeigniter 2.1.3
- hybridauth 2.1.2
- bootstrap 2.3.2
- jquery-1.10.1
- jquery-ui-1.10.3
1. Todo del tirón:
2. La versión separada, mucho más manejable
Elementos que contienen elementos
Elementos que solamente contienen texto
Elementos que pueden tener tanto otros elementos como texto
Elementos vacíos
Indicadores
XML Schema, elementos simples
Los tipos
El tipo boolean
El tipo string y sus derivados
- preserve: mantiene los espacios blancos o caracteres no visibles.
- collapse: quita cualquier caracter no visible (espacios, saltos, etc..)
- replace: sustituye saltos de línea etc por espacios en blanco.
Tipos numéricos
- byte, unsignedByte
- decimal,
- int, unsignedInt,
- integer, negativeInteger (-1,-2,-3,..), nonPositiveInteger (0,-1,-2,...), nonNegativeInteger (0,1,2,...), positiveInteger (1,2,3,...)
- long,unsignedLong
- short,unsignedShort
- enumeration: un conjunto de números
- fractionDigits: total de decimales a mostrar
- maxExclusive: valor máximo EXcluyendo el indicado
- maxInclusive: valor máximo incluyendo el indicado
- minExclusive: valor mínimo EXcluyendo el indicado
- minInclusive: valor mínimo incluyendo el indicado
- pattern: aplicar patrón regex
- totalDigits: total de dígitos a mostrar
- whiteSpace: tratamiendo de espacios en blanco
Las fechas.
Date
El dateTime
Duration, la duración en tiempo
- nY indica n años
- nM n meses
- nD n días
- T En el caso de que vayamos indicar un tiempo ponemos la T primero
- nH n horas
- nM n minutos
- nS n segundos
- type="xs:gDay" para representar un día en formato DD
- type="xs:gMonth" para representar un mes en formato MM
- type="xs:gMonthDay" para representar un mes-día en formato MM-DD
- type="xs:gYear" para representar un año en formato YYYY
- type="xs:gYearMonth" para representar un año-mes en formato YYYY-MM
- enumeration
- maxExclusive
- maxInclusive
- minExclusive
- minInclusive
- pattern
- whiteSpace
Otros tipos raros
El binario:
AnyURI
Aplicable para todos
There's two ways to go on this job: my way or the highway.
Ese podría ser el lema de Maven, o como decía la versión traducida de Reservoir Dogs
"Hay dos formas de hacer el trabajo, la mía o la puta calle."
Comienzo con esa cita porque, para qué nos vamos a engañar, esa escena es genial y esa es la típica frase que a veces nos vemos tentados a soltar pero no hacemos por ser correctos. Maven es un poco así, te obliga a hacer las cosas a su manera, pero todo es por tu bien.
Si bien se puede personalizar su forma de funcionar la gente que lo usa te sugiere que mejor no empeñarse en retorcerlo a nuestro gusto.
Deja que Maven conduzca...
La estructura de directorios de un proyecto Maven sería así, no hay que hacerla a mano te la puede generar el propio
Maven o un IDE.
Proyecto/pom.xml
Proyecto/src
Proyecto/src/main
Proyecto/src/main/java/Hola.java
Proyecto/src/main/resources
Proyecto/src/test
Tras ejecutar mvn install, se ejecutarían las siguientes tareas por defecto: procesar recursos si los hubiera, compilar código, compilar y pasar test unitarios si las hubiero, generar un fichero jar e instalarlo en el repositorio local para que otros proyectos lo usen.
En el proyecto se generaría la carpeta Target con el resultado:
Proyecto/target
Proyecto/target/Hola-1.0.jar
Proyecto/target/classes/Hola.class
El contenido del fichero pom.xml es el siguiente, muy mínimo:
Maven es mucho más que una herramienta para automatizar la compilación de código. Se considera como una herramiento para gestionar proyectos de software. Aunque en un primer vistazo nos encontramos con un fichero xml y un comando que pone todo en marcha (como ant), Maven va mucho más allá. Partiendo
de un interfaz único Maven es capaz de resolver las dependencias de los componentes del proyecto y reutiliza infinidad de plugins para resolver cualquier tarea.
La base de Maven es muy pequeña pero sin embargo según las tareas que se le requieran de forma automática se descarga todos los plugins necesario de un repositorio central a uno local. La mayor parte de las tareas de Maven la realizan esos plugins.
Los IDEs tienen soporte para crear proyectos basados en Maven. Netbeans desde hace más tiempo que Eclipse, que por fin
en la versión Kepler parece traer proyectos Maven de serie. Y si es una forma unificada de configurar un poryecto, solamente por eso merece la pena usarlo.
¿Qué es XML?
XML: eXtensible Markup Language
es un subconjunto del SGML (un lenguaje de marcas de propósito general) y es el lenguaje que la w3c recomienda para crear lenguajes de marcas orientados a determinadas funciones. Es una especie de lenguaje como HTML pero en el que las etiquetas las inventamos nosotros.
Dicho de otra forma:
XML es un lenguaje de marcas con el que tenemos libertad total para decidir que etiquetas y atributos metemos. Su principal aplicación es la de intercambio de datos entre sistemas y aplicaciones.
Este es el aspecto de un fichero XML
<?xml version="1.0" encoding="UTF-8"?>
<libro>
<titulo>Neuromante</titulo>
<autor>William Gibson</autor>
<isbn>84-450-7405-9</isbn>
<fecha edicion=”2”>1985-12-4</fecha>
<paginas>450</paginas>
</libro>
¿Y para que necesito esto?
- Es el lenguaje ideal para el intercambio de información ya que tiene estas ventajas
- Es texto plano
- Es legible por humanos y máquinas
- Es muy simple
- Es muy útil para representar tipos de datos (registros, arboles, listas)
- Es un estándar abierto
- La mayoría de lenguajes tienen librerías para tratar XML
Cómo hacer que XML siga un esquema determinado: DTD
(Igual esquema no es la palabra apropiada, pero en fin)
Si nos interesa podemos hacer que un documento XML cumpla un determinado esquema de etiquetas y atributos. Ese esquema esta definido por un DTD. Esa definición puede ir dentro del XML o estar referenciado así:
<!DOCTYPE libro SYSTEM "libros.dtd">
El DTD es un Document Type Definition, en definitiva un fichero que indica el formato que debe tener un contenido XML, indicando las etiquetas, atributos, jerarquía etc..
Este sería un ejemplo de DTD para el XML anterior:
<!ELEMENT libro (titulo,autor,isbn,fecha,paginas)>
<!ELEMENT titulo (#PCDATA) >
<!ELEMENT autor (#PCDATA) >
<!ELEMENT isbn (#PCDATA) >
<!ELEMENT fecha (#PCDATA) >
<!ATTLIST fecha edicion CDATA "1">
<!ELEMENT paginas (#PCDATA) >
Requisitos que debe cumplir un fichero XML
Estas son las propiedades que debe tener un fichero XML considerarse como tal:
1.-Debe estar BIEN FORMADO (well formed)
-Siempre debe tener un elemento raíz
-Todas las etiquetas deben cerrarse
-Todos los atributos llevan comillas ' o “.
-Las etiquetas se anidan pero nunca se solapan
-Las etiquetas son case-sensitive, no hay que mezclar mayúsculas con minúsculas
2.-En caso de depender de un DTD, debe ser VÁLIDO
Una ventaja muy obvia de XML es que podemos crear un fichero de propiedades, de configuración, de lo que sea y no necesitamos crear desde 0 código para verificar y validar que ese fichero es correcto. Todo ese trabajo nos lo dan las librerías de las que disponemos para gestionar XML. Por ejemplo en java si abrimos un fichero xml y esté no está bien formado o no es válido nos los dirá de forma inmediata.
Los DTD se quedan un poco cortos si necesitamos un mayor control de los tipos de datos que metemos en el fichero XML. Con un DTD podemos decir que vale, en tal etiqueta hay un texto, pero ese texto puede ser cualquier cosa. ¿Podemos controlar que sea número, texto o que siga un patrón predeterminado?
La respuesta es XSD, pero eso amigos, es otra historia para otro día.
xml sigue vigente, y de qué manera. Basta con ver android y sus inifinitos ficheros XML para configurar hasta el último texto de la etiqueta más remota. También en muchos frameworks son frecuentes los ficheros de configuración aunque hay cierta lucha con la opción XML o las anotaciones. En un principio cualquier cosa configurable se hacía en un fichero XML aparte, y de tanto exceso hay quien tratade volver atrás.
Recientemente me disponía a poner orden en la sección de descargas y software de este sitio donde no hay más que vaporware, pruebas de concepto y algunas ideas disparatadas. Casi todas ellas están dejadas ahí por si a alguien le servía algo como idea o por si algún trozo de código podía ser útil para uno mismo: cómo leer un fichero properties, cómo hacer el tema de locales en php, cómo hacer un bot de irc en perl para tomar el pelo a los salidos, en fin un cajón desastre.
Uno de las tonterías que tenía por ahí era una vieja idea de montar un motor de inferencia propio. La inteligencia artificial fue de las últimas asignaturas de la carrera que se me atravesó un poco con uno de los exámenes más jodidos de todos al menos en la facultad de Donosti: mezclaba programación funcional en lisp, programación lógica con prolog y programar una especie de sistemas expertos sencillos en clisp, y no recuerdo qué cosas más -oscuras o mejor dicho difusas ;)-. Un horror. Es una asignatura que bien dada puede ser fascinante pero tal cual te la dan lo que acabas haciendo es procurar preparar el examen, más que aprender algo útil.
El caso es que el tema de los motores de inferencia, los sistemas expertos me parecía algo más interesante para aplicar a problemas reales. Por ejemplo tenía la idea de crear un administrador de sistemas virtual que en función del estado del sistema fuera capaz de tomar decisiones y aplicar los comandos oportunos.Esto quizá vino inspirado por una peli de serie B llamada Webmaster donde sale algo parecido: un sysadmin que transmite sus ordenes a un ente virtual llamado EGO que va aprendiendo de su amo y mantiene y supervisa los servidores.
Comencé desarrollando una especie de motor de inferencia en perl cuyo código debe andar por sourceforge desde al año 2000 (madre del amor hermoso) y que lo mismo ya está desaparecido. Si lo viera sería incapaz de reconocer la paternidad del mismo ya que perl es un lenguaje que por mucho que te esfuerces en ponerlo claro queda inevitablemente sucio (demasiados caracteres especiales).
En el 2001 la humanidad todavía no había llegado a Jupiter como predijo Clarke, así que me dediqué a esa misma idea y la traté de pasar a Java manteniendo en mismo nombre, inferenczy,evidente para mí pero sin duda rebuscado para cualquiera que no haya leído la saga del Necroscopio de Brian Lumley, o sea la gran mayoría de la gente normal informática o no. Justo cuando estaba revisando ese código me encontré que inferenczy estaba montado sobre otro proyecto que pensaba que estaba perdido sin remedio: Ozone.
OOO = O3 = Ozone
Era por las tres O, de Object Oriented Operative System. Tras ese nombre tan pretendidamente molón lo que trataba de hacer es un sistema operativo hecho enteramente en java, todo de consola claro. En su día ya existía alguna cosa así JavaOS se me ocurre y seguramente ahora habrá miles de ellos. Me ha sorprendido un poco cómo compliqué el desarrollo de ese sistema seguramente inspirado en el entorno de trabajo que me rodeaba en esa época: en Madrid trabajando para una una de las más célebres cárnicas (AXPE) que a su vez me tenía en la mítica picadora de carne llamada Andersen (¡¡toma combo breaker!!). Ese era un proyecto en el que los pérfidos gerentes de Andersen le habían vendido a Safei un proyecto monstruoso con un framework del mal donde TODO era XML y donde se metía lo típico de la época: Java, Oracle, EJB, Unix (no linux) y ante todo XML everywhere: los formularios web estaban definidos en xml. Las consultas a BBDD estaban definidas en xml, etc... una época en la que, te lo creas o no, todavía se fumaba en la oficina.
Así que Ozone e inferenczy iban a usar XML. Y por supuesto JDBC, que siempre queda más profesional. Como digo hace unas semanas me bajé el código y eché un ojo a los ficheros de log que generaba el sistema y esto fue lo que me encontré:
Wed Sep 05 11:30:06 CEST 2001> <Kernel> Kernel loaded.
Wed Sep 05 11:30:06 CEST 2001> <Kernel> starting init...
Wed Sep 05 11:30:06 CEST 2001> <Init> Init started. [pid: 1]
Wed Sep 05 11:30:06 CEST 2001> <Init> Init completed succesfully.
Wed Sep 05 11:30:06 CEST 2001> <DBConnection> starting...
Wed Sep 05 11:30:06 CEST 2001> <DBConnection> Connected to DB
Wed Sep 05 11:30:06 CEST 2001> <DBConnection> DB Operations interface set to: SQL
Wed Sep 05 11:30:06 CEST 2001> <DBOperationsSQL> SQL SELECT successful: select * from personas
Wed Sep 05 11:30:06 CEST 2001> <DBConnection> started. [pid: 2]
Madre mía, 5 de septiembre de 2001. Y al poco se ve esto:
Thu Sep 06 08:19:06 CEST 2001> <Kernel> Kernel loaded.
Thu Sep 06 08:19:06 CEST 2001> <Kernel> starting init...
Thu Sep 06 08:19:06 CEST 2001> <Init> Init started. [pid: 1]
Thu Sep 06 08:19:06 CEST 2001> <Init> Init completed succesfully.
Thu Sep 06 08:19:06 CEST 2001> <DBConnection> starting...
Thu Sep 06 08:19:07 CEST 2001> <DBConnection> Connected to DB
Thu Sep 06 08:19:07 CEST 2001> <DBConnection> DB Operations interface set to: SQL
Thu Sep 06 08:19:07 CEST 2001> <DBConnection> started. [pid: 2]
Wed Sep 12 11:35:06 CEST 2001> <Kernel> Kernel loaded.
Wed Sep 12 11:35:07 CEST 2001> <Kernel> starting init...
Wed Sep 12 11:35:07 CEST 2001> <Init> Init started. [pid: 1]
Wed Sep 12 11:35:07 CEST 2001> <Init> Init completed succesfully.
Wed Sep 12 11:35:07 CEST 2001> <DBConnection> starting...
Wed Sep 12 11:35:07 CEST 2001> <DBConnection> Can't connect to DB
Wed Sep 12 11:35:07 CEST 2001> <DBConnection> DB Operations interface set to: SQL
Wed Sep 12 11:35:07 CEST 2001> <DBConnection> started. [pid: 2]
Parece que tras el 11 de septiembre el mundo se derrumbaba pero yo seguía a mi rollo. ¡¡Oh cielos no! ¡¡No me conectaba a la BBDD!!
El caso es que, años después, lo volvía a ejecutar tirando de un script BAT que había para tal efecto. Y esto sucedió:
Tue Sep 18 09:26:00 CEST 2001> <Kernel> Kernel loaded.
Tue Sep 18 09:26:00 CEST 2001> <Kernel> starting init...
Tue Sep 18 09:26:00 CEST 2001> <Init> Init started. [pid: 1]
Tue Sep 18 09:26:00 CEST 2001> <SystemXMLReader> Init Data/etc/init.xml parsing.
Tue Sep 18 09:26:00 CEST 2001> <SystemXMLReader> parsed.
Tue Sep 18 09:26:00 CEST 2001> <Init> Loading com.javamercenary.ai.inferenczy.core.DBConnection...
Tue Sep 18 09:26:00 CEST 2001> <Init> Init completed succesfully.
Tue Sep 18 09:26:00 CEST 2001> <DBConnection> starting...
Tue Sep 18 09:26:00 CEST 2001> <DBConnection> Can't connect to DB
Tue Sep 18 09:26:00 CEST 2001> <DBConnection> DB Operations interface set to: SQL
Tue Sep 18 09:26:00 CEST 2001> <DBConnection> started. [pid: 2]
<LOG><DATE>Tue Sep 18 09:28:26 CEST 2001</DATE><MESSAGE><Kernel> Kernel loaded.</MESSAGE></LOG>
<LOG><DATE>Tue Sep 18 09:28:26 CEST 2001</DATE><MESSAGE><Kernel> starting init...</MESSAGE></LOG>
<LOG><DATE>Tue Sep 18 09:28:26 CEST 2001</DATE><MESSAGE><Init> Init started. [pid: 1]</MESSAGE></LOG>
<LOG><DATE>Tue Sep 18 09:28:26 CEST 2001</DATE><MESSAGE><SystemXMLReader> Init Data/etc/init.xml parsing.</MESSAGE></LOG>
<LOG><DATE>Tue Sep 18 09:28:27 CEST 2001</DATE><MESSAGE><SystemXMLReader> parsed.</MESSAGE></LOG>
<LOG><DATE>Tue Sep 18 09:28:27 CEST 2001</DATE><MESSAGE><Init> Loading com.javamercenary.ai.inferenczy.core.DBConnection... </MESSAGE></LOG>
<LOG><DATE>Tue Sep 18 09:28:27 CEST 2001</DATE><MESSAGE><Init> Init completed succesfully.</MESSAGE></LOG>
<LOG><DATE>Tue Sep 18 09:28:27 CEST 2001</DATE><MESSAGE><DBConnection> starting...</MESSAGE></LOG>
<LOG><DATE>Tue Sep 18 09:28:27 CEST 2001</DATE><MESSAGE><DBConnection> Can't connect to DB</MESSAGE></LOG>
<LOG><DATE>Tue Sep 18 09:28:27 CEST 2001</DATE><MESSAGE><DBConnection> DB Operations interface set to: SQL</MESSAGE></LOG>
<LOG><DATE>Tue Sep 18 09:28:27 CEST 2001</DATE><MESSAGE><DBConnection> started. [pid: 2]</MESSAGE></LOG>
<LOG><DATE>Fri May 31 23:47:48 CEST 2013</DATE><MESSAGE><Kernel> Kernel loaded.</MESSAGE></LOG>
<LOG><DATE>Fri May 31 23:47:48 CEST 2013</DATE><MESSAGE><Kernel> starting init...</MESSAGE></LOG>
<LOG><DATE>Fri May 31 23:47:48 CEST 2013</DATE><MESSAGE><Init> Init started. [pid: 1]</MESSAGE></LOG>
<LOG><DATE>Fri May 31 23:47:48 CEST 2013</DATE><MESSAGE><SystemXMLReader> Init Data/etc/init.xml parsing.</MESSAGE></LOG>
<LOG><DATE>Fri May 31 23:47:49 CEST 2013</DATE><MESSAGE><SystemXMLReader> parsed.</MESSAGE></LOG>
<LOG><DATE>Fri May 31 23:47:49 CEST 2013</DATE><MESSAGE><Init> Loading com.javamercenary.ai.inferenczy.core.DBConnection... </MESSAGE></LOG>
<LOG><DATE>Fri May 31 23:47:49 CEST 2013</DATE><MESSAGE><DBConnection> starting...</MESSAGE></LOG>
<LOG><DATE>Fri May 31 23:47:49 CEST 2013</DATE><MESSAGE><Init> Init completed succesfully.</MESSAGE></LOG>
<LOG><DATE>Fri May 31 23:47:49 CEST 2013</DATE><MESSAGE><DBConnection> Can't connect to DB</MESSAGE></LOG>
<LOG><DATE>Fri May 31 23:47:49 CEST 2013</DATE><MESSAGE><DBConnection> DB Operations interface set to: SQL</MESSAGE></LOG>
<LOG><DATE>Fri May 31 23:47:49 CEST 2013</DATE><MESSAGE><DBConnection> started. [pid: 2]</MESSAGE></LOG>
Hay dos cosas: se ve que el 18 de septiembre, inmerso en la locura de XML cambié el formato del fichero de log usando tags (MAL, en mayúsculas) con la vaga idea de que quizá en algún momento podría interesar parsear los ficheros de log para facilitar su análisis. Cosa que sí es útil. La revisión y procesamient de logs puede servir para sacar estadísticas por ejemplo como hacen algunos analizadores web como webalizer.
La otra cosa, algo más anecdótica es el salto temporal en el fichero de log desde:
Tue Sep 18 09:28:27 CEST 2001
Hasta
Fri May 31 23:47:48 CEST 2013
Madre mía, 12 años nos contemplan. Y el código seguía funcionando en una máquina virtual mucho más moderna.
Bueno, en lugar de empezar poniendo un diagrama de clases, voy a ir a haciendo algo de ingeniería inversa para poder entender cómo narices funcionaba esto. Y todo parte de dos ficheros *.bat, uno para compilar y el otro para ejecutar. Efectivamente, ignoraba la existencia de herramientas como ANT, si es que existían entonces que no lo sé. El caso es que el fichero de compilación hacía lo siguiente:
@echo off
@REM Copyright (c) 2000 Pedro Alcazar, Inc. All Rights Reserved.
@REM Adjust these variables to match your environment
set CLASSES=src/core/*.java src/api/*.java src/ie/*.java
set PATH=%PATH%;c:\jbuilder4\jdk1.3\bin
if "" == "%JAVA_HOME%" set JAVA_HOME=c:\jbuilder4\jdk1.3
set MYCLASSPATH=%JAVA_HOME%\lib\classes.zip;.;c:\weblogic\lib\parser.jar
echo Build %CLASSES% ...
javac -d . -classpath %MYCLASSPATH% %CLASSES%
echo [ DONE ]
pause
Madreeee! ¡El Jbuilder! ¡El jdk1.3! ¡El weblogic! ¿Y quién era Pedro Alcazar? ¡Era yo! Si quieres saber por qué... pues en fin.
A ver el de ejecución:
@echo off
@REM Copyright (c) 2000 Pedro Alcazar, Inc. All Rights Reserved.
@REM Adjust these variables to match your environment
set STARTCLASS=com.javamercenary.ai.inferenczy.core.Boot
set PATH=%PATH%;c:\jbuilder4\jdk1.3\bin
if "" == "%JAVA_HOME%" set JAVA_HOME=c:\jbuilder4\jdk1.3
set MYCLASSPATH=%JAVA_HOME%\lib\classes.zip;./lib/parser.jar;.
echo running %STARTCLASS%
java -classpath %MYCLASSPATH% %STARTCLASS%
pause
Bueno vale, parecido pero ya vemos un inicio:
com.javamercenary.ai.inferenczy.core.Boot
Cómo mola lo de javamercenary, y lo de core, jajaja, qué pretencioso es todo. Bueno, a ver qué narices hacía la clase Boot:
package com.javamercenary.ai.inferenczy.core;
/**
* Título: Inference Engine
* Descripcion:
* Copyright: Copyright (c) 2001
* Empresa:
* @author P. Al.
* @version 1.0
*/
public class Boot {
/**
* method
*/
Boot () {
}
public static void main (String args[]) {
System.out.println("INFeReNCZy (c) P. Al. Madrid September 2001");
System.out.println("INFeReNCZy Bootstrap...");
new Kernel().start();
}
}
Los comentarios javadoc son lo que te metía el jbuilder. Vale, se ve hay un Kernel quese inicia, y tiene pinta de ser un hilo. Vamos a verlo:
package com.javamercenary.ai.inferenczy.core;
/**
* Título: Inference Engine
* Descripcion:
* Copyright: Copyright (c) 2001
* Empresa:
* @author P. Al.
* @version 1.0
*/
import java.util.Hashtable;
import java.util.Vector;
import java.sql.Connection;
public class Kernel extends Thread {
/**
* KERNEL ATTRIBUTES
*/
// process table
private final static Hashtable _PROCESSES = new Hashtable();
// system properties: loglevel, multiuser,...
private InferenczyProperties _SYSTEM_PROPERTIES = new InferenczyProperties();
// system interface
private SystemInterface _SI = null;
// log service
private static final Log _LOG = new Log();
// console output
private static final Printer _PRINTER = new Printer();
// XML Reader
private static final SystemXMLReader _XML_READER = new SystemXMLReader();
// database connection
private Connection _DBCONNECTION = null;
// database operations interface
private DBOperationsInterface _DBOPERATIONS_INTERFACE = null;
/**
* method
*/
Kernel () {
}
/**
* run the Kernel
*/
public void run () {
// first of all, load system properties.
if (!this.loadProperties()) {
System.err.println("Failed to load Properties file.");
}
_SI = new SystemInterface(this);
//setting properties.
_LOG.setProperties(_SI);
_PRINTER.setProperties(_SI);
_XML_READER.setProperties(_SI);
_LOG.log(1,"<Kernel> Kernel loaded.");
// now run first process: init (pid:1)
_LOG.log(1,"<Kernel> starting init...");
startProcess("com.javamercenary.ai.inferenczy.core.Init",1,1,1,1,1,"Init program");
}
/**
* loadProperties
*/
private boolean loadProperties () {
return _SYSTEM_PROPERTIES.loadProperties();
}
/**
* getProperties
*/
public InferenczyProperties getProperties () {
return _SYSTEM_PROPERTIES;
}
/**
* startProcess
* return 0 if everything works well
*/
public int startProcess (String name,int PID,int UID,int GID,int STATE,int PRIORITY, String P_INFO) {
Object o = null;
try {
o = Class.forName(name).newInstance();
} catch (ClassNotFoundException cnfe) {
_LOG.log(1,"Error on instantiation. Class not Found."+cnfe.getMessage());
return -1;
} catch (IllegalAccessException iae) {
_LOG.log(1,"Error on instantiation.Illegal Access"+iae.getMessage());
return -2;
} catch (InstantiationException ie) {
_LOG.log(1,"Error on instantiation."+ie.getMessage());
return -3;
}
try {
if (((Process) o).setAttributes(PID,UID,GID,STATE, PRIORITY,P_INFO,this._SI)) {
addProcess(((Process)o));
((Process) o).start();
}
return 0;
} catch (Exception e) {
removeProcess(new Integer(((Process)o).getPID()));
_LOG.log(1,"Error on instantiation."+e.getMessage());
return -4;
}
}
/**
* addProcess
*/
private boolean addProcess (Process p) {
try {
_PROCESSES.put(new Integer(p.getPID()),p);
return true;
} catch (Exception e) {
_PRINTER.print(-1,"Error starting process.\n");
return false;
}
}
/**
* removeProcess
*/
public boolean removeProcess (Integer pid) {
try {
_PROCESSES.remove(pid);
return true;
} catch (Exception e) {
_PRINTER.print(-1,"Error deleting process.\n");
return false;
}
}
/**
* getProcessTable
*/
public Hashtable getProcessTable () {
return _PROCESSES;
}
/**
* log
*/
public boolean log (int loglevel, String message) {
return _LOG.log(loglevel,message);
}
/**
* print
*/
public void print (int flag, String message) {
_PRINTER.print(flag,message);
}
/**
* setDBConnection
*/
public void setDBConnection (Connection conn) {
this._DBCONNECTION = conn;
}
/**
* getDBConnection
*/
public Connection getDBConnection () {
return this._DBCONNECTION;
}
/**
* setDBOperations
*/
public void setDBOperationsInterface (DBOperationsInterface dbo) {
this._DBOPERATIONS_INTERFACE = dbo;
}
/**
* getDBOperations
*/
public DBOperationsInterface getDBOperationsInterface () {
return this._DBOPERATIONS_INTERFACE;
}
/**
* readData
* @param String filename
* @param String[] elements
* @return Hashtable
*/
public Hashtable readData (String filename, String[] elements) {
return this._XML_READER.initParse(filename,elements);
}
/**
* readData
* @param String filename
* @param String field
* @return Hashtable
*/
public Vector readData (String filename,String field) {
return this._XML_READER.initParse(filename,field);
}
}//end kernel
Vaya vaya, si es una especie de sistema operativo.
Tiene properties, un sistema de logs, un printer que será para sacar mensajes por algún lado, una tabla de procesos, y un método para crear nuevos procesos que hace uso del Reflection. Y aparte de getters y setters tiene como peculiar un interfaz para una BBDD y un lector de XML.
Básicamente el Kernel pone en marcha nuevas instancias de programas que heredan de la clase Process, la cual tiene esta pinta:
package com.javamercenary.ai.inferenczy.core;
/**
* Título: Inference Engine
* Descripcion:
* Copyright: Copyright (c) 2001
* Empresa:
* @author P. Al.
* @version 1.0
*/
public abstract class Process extends Thread {
/**
* attributes
*/
private int PID = -1 ;
private int UID = 0;
private int GID = 0;
private int STATE = 0;
private int PRIORITY = 0;
private String P_INFO = "";
private long START_DATE;
private SystemInterface _SI = null;
/**
* constructors
*/
public Process () {
this.START_DATE = System.currentTimeMillis();
}
public Process (int PID,int UID,int GID,int STATE,int PRIORITY, String P_INFO, SystemInterface _SI) {
this.PID = PID;
this.UID = UID;
this.GID = GID;
this.PID = PID;
this.PRIORITY = PRIORITY;
this.P_INFO = P_INFO;
this._SI = _SI;
}
public boolean setAttributes (int PID,int UID,int GID,int STATE,int PRIORITY, String P_INFO, SystemInterface _SI) {
if (PID == -1) return false;
this.PID = PID;
this.UID = UID;
this.GID = GID;
this.PID = PID;
this.PRIORITY = PRIORITY;
this.P_INFO = P_INFO;
this._SI = _SI;
return true;
}
public int getPID (){
return PID;
}
public int getUID () {
return UID;
}
public int getGID () {
return GID;
}
public int getSTATE () {
return STATE;
}
public int setSTATE (int state) {
return STATE = state;
}
public int getPRIORITY () {
return PRIORITY;
}
public int setPRIORITY(int priority) {
return PRIORITY = priority;
}
public long getSTART_DATE() {
return START_DATE;
}
public String getP_INFO () {
return P_INFO;
}
public SystemInterface get_SI () {
return _SI;
}
public String setP_INFO(String p_info) {
return P_INFO = p_info;
}
}
Un Thread.
El primer proceso que inicia el kernel es, como no podía ser menos Init. Y este hereda de process y lo que hace básicamente es cargar en el kernel una serie de procesos que tiene indicado dentro de init.d:
package com.javamercenary.ai.inferenczy.core;
/**
* Título: Inference Engine
* Descripcion:
* Copyright: Copyright (c) 2001
* Empresa:
* @author P. Al.
* @version 1.0
*/
import java.util.Vector;
public class Init extends Process {
/**
* method
*/
public Init () {
super();
}
public Init (int PID,int UID,int GID,int STATE,int PRIORITY, String P_INFO, SystemInterface _SI) {
super(PID,UID,GID,STATE,PRIORITY,P_INFO, _SI);
}
/**
* run method
*/
public void run () {
get_SI().log(1,"<Init> Init started. [pid: "+this.getPID()+"]");
loadProcesses();
while (true) {
}
}
/**
* loadProcesses
* load processes from init.d
*/
private boolean loadProcesses () {
String line = "";
int cont = 2;
boolean errors = false;
Vector vclasses = null;
try {
vclasses = get_SI().readData(get_SI().getProperty("init.d"),"CLASSNAME");
for (int i = 0;i<vclasses.size();i++) {
get_SI().log(1,"<Init> Loading "+vclasses.elementAt(i)+"... ");
if (get_SI().startProcess((String)vclasses.elementAt(i),cont++,1,1,1,1,line) < 0)
errors = true;
}
if (errors)
get_SI().log(1,"<Init> Init finished with errors. Check init.d file.");
else
get_SI().log(1,"<Init> Init completed succesfully.");
return true;
} catch (Exception e) {
get_SI().log(1,"Failed loadin properties .Error: "+e.getMessage());
return false;
}
}
}
El sistema gira en torno al kernel. Y en resumen los procesos como el init y los recursos del sistema se comunican con el kernel a través de un intermediario llamado SystemInterface. En el diagrama UML puedes hacerte una vaga idea de cómo está montado, y verás que las clases se acoplan y que todo es un poco infernal. Pero como digo... era joven e incosciente. Ahora ya soy simplemente joven y plenamente inconsciente. ¿o era simplemente inconsciente?
Delirio total
Ojo que lo del sistema operativo no era más que una base para montar el motor de inferencia. Y lo pretencioso del tema es que quería crear programas escritos en XML. Es decir, era una especie de lenguaje de programación genérico, al que por ejemplo se le podría hipotéticamente aplicar un XSLT y convertir en un lenguaje concreto. Por ejemplo de un programa.xml podriamos tener un Programa.java y un Programa.cpp.
Todo el proyecto está ahora subido a google code. Echa un ojo a la carpeta Data donde encontrarás el DTD: http://code.google.com/p/ozone/
Para descargar por git:
git clone https://code.google.com/p/ozone/
O puedes descargar el zip original:
http://pello.info/filez/inf.zip
aunque existe otro original en alguna parte con otros procesos como el login y un shell... pero quién sabe dónde.
Java i18n Internationalization
¿Qué por qué se llama i18n? búscalo y verás, qué cosas.
A diferencia de otros lenguajes la internacionalización de programas en java, al menos la forma básica que trae la plataforma por defecto te permite hacer de todo (fechas, monedas, traducción de texto con parámetros) pero la forma es cuando menos engorrosa.
Lo que he puesto aquí es el típico churro que muestra cómo hacer varias cosas: detectar el locale del sistema, aplicar el que nosotros queramos, mostrar números y monedas según el locale, las fechas, etc. y por supuesto, mostrar mensajes en distintos idiomas, con o sin parámetros.
si ahondamos un poco en la documentación oficial veremos que hay dos tipos de internacionalizaciones, una es la que veremos aquí pero hay otra (ListResourceBundle) en la que hay que crear ficheros *.class para la internacionalización.
Otra cosa curiosa es que los ficheros properties con los mensajes deben estar en el classpath como si fueran clases. Por cada idioma que queremos meter debemos crear un fichero con mensajes, incluyendo uno que será el que se aplique en caso de no encontrar el locale elegido en el programa.
Messages.properties
Este sería el fichero por defecto:
# this is a comment
start = Starting program
end = Program ended
hello = Hello
name = My name is {0}
name2 = My name is {0} and Im {1,number,integer} years old \
and I was born in {2,date,long} at {2,time,short} \
and I weighed {3,number}
Message_en_US.properties
Este sería la versión inglesa-USA:
# this is a comment
start = Starting program
end = Program ended
hello = Hello
name = My name is {0}
name2 = My name is {0} and Im {1,number,integer} years old \
and I was born in {2,date,long} at {2,time,short} \
and I weighed {3,number}
Message_es_ES.properties
Y la versión española, ole ole y ole qué arte :)
# this is a comment
start = Iniciando programa
end = Programa terminado
hello = Hola
name = Mi nombre es {0}
name2 = Mi nombre es {0} y tengo {1,number,integer} años\
y nací el {2,date,long} a las {2,time,short}\
y pesé {3,number}
El programa
Un churro con todas las pruebas que se me ocurrían, aunque sé que faltan algunas.
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.util.Currency;
import java.util.Date;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Scanner;
/**
* Shows how to write a program with messages in different languages
* NOTE: message files (*.properties) must be located in the classpath
* like a *.class file
* @author Pello Altadill
* @greetz fat-free milk drinker
* http://butterbeliever.com/fat-free-dairy-skim-milk-secrets/
*/
public class InternationalizationSample {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Locale locale = Locale.getDefault();
String language = locale.getDisplayLanguage();
String country = locale.getDisplayCountry();
Scanner reader = new Scanner(System.in);
Integer integerNumber = new Integer(160666);
Double doubleNumber = new Double(1666.42);
NumberFormat numberFormatter;
DateFormat dateFormatter;
Currency currency;
String languageCode = System.getProperty("user.language");
String countryCode = System.getProperty("user.country");
System.out.println("Lang: " + language + ", country: " + country);
System.out.println("Lang: " + languageCode + ", country: " + countryCode);
System.out.println("Give me lang code (en, es, eu): ");
languageCode = reader.nextLine();
System.out.println("Give me country code (EN, ES, EU): ");
countryCode = reader.nextLine();
// Let's show messages in selected language
ResourceBundle messages;
System.out.println("Setting locales to: " + languageCode +"_"+countryCode);
locale = new Locale(languageCode, countryCode);
messages = ResourceBundle.getBundle("Messages", locale);
System.out.println(messages.getString("start"));
System.out.println(messages.getString("hello"));
System.out.println(messages.getString("end"));
numberFormatter = NumberFormat.getNumberInstance(locale);
dateFormatter = DateFormat.getDateInstance(DateFormat.LONG, locale);
// currency = Currency.getInstance(locale);
System.out.println("Numbers: " + numberFormatter.format(integerNumber));
System.out.println("Number Double: " + numberFormatter.format(doubleNumber));
//numberFormatter = NumberFormat.getCurrencyInstance(locale);
//System.out.println("Currency: " + currency);
//System.out.println("Money: " + numberFormatter.format(doubleNumber));
// PARAMETERS!!!
// For messages with parameters we use MesssageFormat
// This will be the param to fill de message
Object[] messageParams = {
"Prince"
};
MessageFormat formatter = new MessageFormat("");
formatter.setLocale(locale);
formatter.applyPattern(messages.getString("name"));
System.out.println(formatter.format(messageParams));
// Format samples: http://docs.oracle.com/javase/7/docs/api/java/text/MessageFormat.html
Object[] messageParams2 = {
"Prince",
new Integer(45),
new Date(),
new Double(3.4)
};
formatter = new MessageFormat("");
formatter.setLocale(locale);
formatter.applyPattern(messages.getString("name2"));
System.out.println(formatter.format(messageParams2));
}
}
subscribe via RSS