jueves, 25 de octubre de 2012

El problema de la documentacion

Cuando se esta desarrollando un proyecto aparece la informácion mas importante de todas: como se ha afrontado un problema, detalles sobre tareas especificas (por ejemplo, este expediente es valido si es de tipo A y B y la fecha de expiracion es menor que la fecha actual + el parametro ... a que te suena?), etc.. Esta informacion es la mas importante pero no queda reflejada en ningun sitio ya que, en la inmensa mayoria de los casos, no queda reflejada en ningun sitio. Solo queda reflejado en el "conocimiento popular" de los miembros del proyecto que estan todo el dia con el desarrollo. Esto plantea una serie de problemas:


  • No hay axima fijo para todos. La informacion queda recogida por cada miembro del equipo y su libre interpretacion por lo que al final tenemos varias verdades muy parecidas sobre el mismo asunto.
  • Si un miembro del equipo se va entonces la informacion se pierde.
  • Con el tiempo las cosas se olvidan y se degrada la informacion.
¿Entonces la solucion seria dejar reflejada la informacion en documentos? Esta seria la opción mas logica pero tambien plantea una serie de problemas de peso:

  • El sistema de informacion varia de forma y de tamaño con mucha rapido por lo que mantener actualizada la documentacion resulta dificil. Y no solo el problema es mantenerlo "rapido" es que encima todos los miembros del equipo tendrian que volver a leerlo TODO "rapido" y con mucha frecuencia.
  • Es una tarea dificil documentar ya que hay que expresarse de una manera que no sea demasiado tediosa (ya que si no el lector se cansara de leer) y que no sea demasiado abreviada (ya que si no el lector no se enterara).
Al final, la opcion que se toma es ¿Por que documentar si le puedo preguntar a alguien o lo puedo mirar en el codigo?

lunes, 20 de agosto de 2012

Drag and Drop en JavaFX 2.0

Hola

Os pongo un enlace donde hay un ejemplo de como implementar el drag and drop.

http://blog.ngopal.com.np/2011/06/09/draggable-node-in-javafx-2-0/

Un saludo

viernes, 17 de agosto de 2012

Sistema de log

Cuando se esta desarrollando una aplicación a menudo se comente el fallo de tomarse en serio el log cuando la aplicación esta muy avanzada. El log hay que usarlo desde el principio y siempre hay que estar seguro que se esta generando como se desea.

Hay que establecer una política de mensajes de tal manera que muestre información util para los desarrolladores. Esto es importante ya que no hay que confundir un log con un sistema de auditoria. Los sistemas de auditoria muestran las operaciones que se han realizado, con que datos y como han acabado y un log recoge información util para el equipo tecnico que indican datos sobre la implementacion, el estado de la aplicación, fallos, etc... Es decir, la auditoria esta orientado a negocio y el log al técnico.

Un error a eliminar del log es el sintoma del fallo ciclico. Estos log se corresponden a procesos automáticos (no requieren interaccion del usuario como pulsar un boton, etc..)  y que informan de un hecho (ya sea fallo o que ha podido realizar la tarea).

Por ejemplo, un proceso automatico que intenta conectar con una IP para enviarle un fichero xml y lo hace cada 5 segundos.

Si acierta el log dice :

[TareaEnviaXML] - Tratando de enviar el fichero 00222AC.xml
[TareaEnviaXML] - Fichero 00222AC.xml enviado a 127.0.0.1


Si falla dice log dice :

[TareaEnviaXML] - Tratando de enviar el fichero 00222AC.xml
[TareaEnviaXML] - El fichero 00222AC.xml no se ha podido enviar a 127.0.0.1 debido a ....

Y uno de estas dos pares lineas se escribe el log cada 5 segundos. Al final se tiene

[TareaEnviaXML] - Tarea funcionando....

[TareaEnviaXML] - Tratando de enviar el fichero 70222AC.xml
[TareaEnviaXML] - Fichero 70222AC.xml enviado a 127.0.0.1


[TareaEnviaXML] - Tratando de enviar el fichero 10222AC.xml
[TareaEnviaXML] - Fichero 10222AC.xml enviado a 127.0.0.1

[TareaEnviaXML] - Tratando de enviar el fichero 20222AC.xml

[TareaEnviaXML] - Tratando de enviar el fichero 00222AC.xml
[TareaEnviaXML] - El fichero 00222AC.xml no se ha podido enviar a 127.0.0.1 debido a X

[TareaEnviaXML] - Fichero 20222AC.xml enviado a 127.0.0.1
[TareaEnviaXML] - Tratando de enviar el fichero 30222AC.xml
[TareaEnviaXML] - Fichero 30222AC.xml enviado a 127.0.0.1

[TareaEnviaXML] - Tratando de enviar el fichero 00222AC.xml
[TareaEnviaXML] - El fichero 00222AC.xml no se ha podido enviar a 127.0.0.1 debido a X
...........
Asi el log se hará enorme y realmente no aporta tanta información,  es decir si el proceso ha cumplido con el fichero 70222AC.xml en realidad no necesito saberlo en el log. Si fallo para el fichero 00222AC.xml entonces si, pero si luego falla por lo mismo en realidad tampoco necesito ver el log para saberlo, lo que realmente se necesita es ver cuando a funcionando o si ha fallado por otra cosa. Por lo que el log quedaria:

[TareaEnviaXML] - Tarea funcionando....

[TareaEnviaXML] - Tratando de enviar el fichero 00222AC.xml
[TareaEnviaXML] - El fichero 00222AC.xml no se ha podido enviar a 127.0.0.1 debido a X

[TareaEnviaXML] - Tratando de enviar el fichero  00222AC .xml
[TareaEnviaXML] - Fichero  00222AC .xml enviado a 127.0.0.1

y ya esta. O:




[TareaEnviaXML] - Tarea funcionando....

[TareaEnviaXML] - Tratando de enviar el fichero 00222AC.xml
[TareaEnviaXML] - El fichero 00222AC.xml no se ha podido enviar a 127.0.0.1 debido a X

[TareaEnviaXML] - Tratando de enviar el fichero 00222AC.xml
[TareaEnviaXML] - El fichero 00222AC.xml no se ha podido enviar a 127.0.0.1 debido a Y

[TareaEnviaXML] - Tratando de enviar el fichero 00222AC.xml
[TareaEnviaXML] - El fichero 00222AC.xml no se ha podido enviar a 127.0.0.1 debido a X



[TareaEnviaXML] - Tratando de enviar el fichero  00222AC .xml
[TareaEnviaXML] - Fichero  00222AC .xml enviado a 127.0.0.1




Esto representa un log mas pequeño que muestra la misma informacion.



jueves, 16 de agosto de 2012

Software parts dependency research(I)



When the develop team is in design phase have to think a lot of thing but there are two concepts that are the most important concepts. In addition, it is a good beginning for the design approach starting think in these concepts.

These concepts are:
  •          Which are the parts of software?
  •           How coupled are these parts?

Think about that… step by step

Which is the correct way to split the software up into parts? The software splitting can not be a mechanical process because the main factor is the information system that have to be solved by the software and this information system is fully subjective, that is to say:

  •     The costumer have to explain it.
  •          The  develop team have to understand.
  •           The initial approaching, based on costumer/develop team interviews, will change when the software developing have skill that can be review, analyze, etc. In that moment, the fight will begin. Sure.  It will be because the costumer will say:”I don’t want this, this have to be in this way”. The develop team will say:” You said you want this”.  The costumer say:”you didn’t get it, I wanted this”… Do you know the song???   
I show you the “Box split” method for splitting information system up into parts that can be used like parts of the software. The purpose is the split information system process can set the base for development.
1º Step. Information capture process: Like all good development, the information system have to be understood by the team members. Advice: when the developers talk about their work (the software) usually use a technical words that  must not be understood by the  customer. It happened to costumer too. They usually use the their language for telling us that they want. This is good because if they use the their language then the develop team can suppose how the software interface have to be but warning because the customer explanation can be only good for interface. The business logic have to be a deal between the develop team and the customer said in a technical words. Never let the costumer explain the business logic in their language.








martes, 7 de agosto de 2012

El no empezar de cero


Cuando se empieza el desarrollo de una aplicación se puede diseñar la aplicación, se pueden hacer pruebas de concepto (utilizo este framework?, esta tecnología?, etc..), etc… Todo parece maravilloso. YA SE LIARA DESPUES.

Pero en el mundo empresarial lo mas normal es que o que te incorpores a un proyecto ya empezado o que se te obligue a partir de un proyecto ya existente. Esto unido al hecho de que al no conocer el negocio tan bien como la gente que ya estaba en el proyecto hace que si quieres hacer algo mejor, aplicar alguna nueva tecnología, crear un marco de trabajo, etc… Digas cosas como: “Es que no me dejan” , “Ya esta tan mal que no lo puedo cambiar”, “En el próximo proyecto…”    TE SUENA ¿verdad?


Es cierto que si el proyecto se empezara de cero se podrían hacer las cosas de otra manera pero eso no va a pasar por dos motivos principalmente:

-          No se puede asumir el coste (da igual el proyecto, imposible que exista un proyecto que asuma el coste de que lo desarrollado hasta el momento no valga)
-          ¿Quién te dice que lo nuevo que vas a introducir es mejor que lo que ya había? (ojo con esto y no te confies por muy bueno que te parezca lo que quieres poner  que demostrar la mejora de algo a nivel de diseño o explicándolo es muy complicado).

Tienes dos opciones:
-          No propones nada para el proyecto actual pero aprovechas el proyecto actual para conocer el negocio y proponer algo para el siguiente.
-          Cuando tengas claro lo que quieres proponer entonces lo haces para las nuevas tareas que vayan surgiendo. De esto se deduce que TIENE QUE SER COMPATIBLE CON LO QUE YA EXISTE (1).

(1)    El hacer compatible lo que quieres proponer para tu proyecto seguro que limitara la potencia que lo que pretendes pero es la forma de que tus superiores acepten tu propuesta.

viernes, 22 de junio de 2012

Limitación de competencias

La limitación de competencias consiste en determinar de forma lógica quien es el responsable de una determinada funcionalidad de un sistema complejo. Y cuando digo responsable, me refiero a todos los estratos del ciclo de vida de la funcionalidad:
- Desarrollo
          - Mantenimiento
          - Solución de errores
- Etc..
La limitación de competencias es un gran problema ya que, aparte de que es un asunto muy subjetivo, los responsables se ven sujetos a demasiados detalles de muy bajo nivel (lo que costo hacer esto, los problemas que dio lo otro, etc..) y tienden a “barrer para casa”; es decir, a no buscar la mejor solución si no lo que menos trabajo les de.

Por ejemplo, un equipo que se encarga del desarrollo de una página web(PW) y otro de una capa de Web Services(WS) que controla los datos del cliente. Entonces:
1º PW quiere saber los datos de un cliente y WS le dice “llama a la función A con el DNI”.
2º Lo hace y funciona.
3º Se entra en producción y los usuario se dan cuenta que algunos DNI no funcionan. Se le indica a PW. PW se lo dice a WS y este le responde:”Es que si el DNI no esta cuando se llama a la funcion A hay que llamar a la funcion B con el DNI”
4º …. PROBLEMA
Que seria lo correcto: ¿PW cambia la llamada y llamaría a la funcion B? ¿WS cambia la funcion A para llamar a la funcion B y obtener el resultado?

Ambas soluciones tienen pros y contras. Ambas soluciones podrían ser correctas y/o erróneas bajo determinados contextos. Entonces como determinar quien tiene que hacer la modificación? 

La solución mas común es solucionar el problema llegando a un acuerdo entre los responsables de PW y SW y si no se puede llegar a una solución entonces acudir a una figura superior (un jefe de los dos equipos).

Tanto si se llega a un acuerdo como si se acude a una figura superior, es clave la capacidad de hacerse entender por parte de los responsables de cada equipo. Por lo que se puede decir que el resultado de un producto software se ve determinado por las actitudes comunicativas de sus responsables mas que por las habilidades técnicas de estos responsables.

jueves, 17 de mayo de 2012

Manipulacion de bytecode con Javassist. Incluir funcionalidad a las anotaciones.


La reflexión es el método tradicional que ofrece Java para hacer  programación dinámica donde el modo de instanciar objetos y donde y cuando usar los métodos de estas instancias no se conoce en tiempo de compilación. Pero la reflexión presenta dos problemas:

-       No deja manipular el código. Es decir se puede, por ejemplo, definir un método nuevo en tiempo de ejecución.
-       Es muy lento (Mirar articulo http://www.ibm.com/developerworks/java/library/j-dyn0610/)

La manipulación de bytecode permite lo mismo que la reflexión, además se puede incluir código nuevo en tiempo de ejecución y es más rápida que la reflexión.

Existen varios frameworks para manipular bytecode. Yo recomiendo Javassist porque es prácticamente como la reflexión nativa de Java pero de manera ampliada.

El siguiente ejemplo ilustra de manera simple como usar javassist para potenciar el uso de una anotación.

public @interface PonleValor
{
   
}
class Hello {
    
     @PonleValor
     private String valor;
    
    
    public void say() {
        System.out.println("Hello es " + valor);
    }
}


public class Test {
   

     public static void main(String[] args) throws Exception {
        ClassPool cp = ClassPool.getDefault();
        CtClass cc = cp.get("es.trap.Hello");
       
        for (Object field:cc.getClassFile().getFields()){
           
           
           FieldInfo info = (FieldInfo)field;
          
           for (Object atrib :info.getAttributes()){
              
              
              
               if (atrib instanceof AnnotationsAttribute){
              
                   AnnotationsAttribute anota = (AnnotationsAttribute)atrib;
                  
                   String name = anota.getAnnotations()[0].getTypeName();
                   
                   if (name.equals(  "es.indra.trap.PonleValor"))                  
                       cc.getConstructors()[0].insertAfter( "{" + info.getName()+  "= \"Ahora vale algo\"; }" );
               }
                  
               
           }
           
        }
      
        Class c = cc.toClass();
        Hello h = (Hello)c.newInstance();
        h.say();
    }


}

Como se puede ver en ejemplo, si instanciamos la clase Hello con Javassist (como si se hiciera con reflexión) y una de sus variables tiene la anotación PonValor entonces se le pondrá un valor de forma automática.

El resultado si se ejecuta este programa es:

Hello es Ahora vale algo

martes, 8 de mayo de 2012

Obtener peticion HTTP en Java

Una peticion HTTP no es mas que un String que envia un emisor para probocar una respuesta en un receptor.

Si se quiere ver una peticion HTTP lo mas facil es enviarla a un puerto donde este un socket escuchando.

Por ejemplo:

public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {
       ServerSocket server = new ServerSocket(8080);

       Socket so = server.accept();

       DataInputStream ent = new  DataInputStream(so.getInputStream());

       byte [] sal = new byte[256];
       while (ent.read(sal) != 0)
        System.out.println(new String(sal));
      }
}


Si se hace la peticion (por ejemplo con el SOAPUI) a localhost:8080/WS la respuesta seria:

POST /WS HTTP/1.0
Content-Type: text/xml; charset=utf-8
Accept: application/soap+xml, application/dime, multipart/related, text/*
User-Agent: Axis/1.4
Host: localhost:8080
Cache-Control: no-cache
Pragma: no-cache
SOAPAction: "
"
Content-Length: 473

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<wsHola xmlns="http://es.indra.transporte.webservices.cscreplacement.core">

<respuesta>Hola Mundo</respuesta>

</wsHola>
</soapenv:Body>
</soapenv:Envelope>

Y ya esta.

lunes, 9 de abril de 2012

Editor grafico para JavaFX 2.0

Hola

Acabo de ver que Oracle a publicado un editor grafico para JavaFX.
Se puede descargar de aqui.

Cuando pueda le hecho un ojo y os cuento.

Un saludo

jueves, 29 de marzo de 2012

Algo no encaja

Una forma de interpretar la filosofía TDD (Desarrollo orientado a pruebas) es como una metodología que bien planteada lleva “la problemática del resultado” hasta los desarrolladores.

¿Qué es la problemática del resultado? La problemática del resultado es el requerimiento que se le hace a un responsable de proyecto de que el producto tiene que estar. Esta definición parece una afirmación obvia pero encierra uno de los grandes problemas del desarrollo de proyectos. Por su parte el responsable siente como su deber que el producto este listo en un plazo (es decir ve todo el proyecto) mientras que las personas que están a su cargo no lo entienden así ya que entienden que están desarrollando un producto pero solo se sienten responsables de la tarea que estén realizando.

Cuanto mas bajo este una persona en el escalafón del proyecto sus tareas son mas cortas y por lo tanto esa persona ve como su trabajo ya esta hecho cuando termina una tarea determinada (es decir ve solo la tarea que está haciendo en ese momento).

Volviendo con TDD, si la forma de marcar el fin de la tarea de un subordina fuese que “lo que ha desarrollado” cumpla unos determinados ejemplos y no el simple hecho de decirle:”¿has terminado? ” y el diga:”si” entonces no solo conviertes algo subjetivo en al cuantificable (lo subjetivo es el “si creo que esta terminado” y lo cuantificable es un test que se cumple o no se cumple y por lo tanto es cuantificable) es que además haces que el desarrollador entienda que es la problemática del resultado.

domingo, 25 de marzo de 2012

JavaFX 2.0. Vamos a crear una historia. Parte II

Ahora vamos con las implementaciones. Por ahora voy a incluir las implementaciones de actor y de la cabeza. No hay cuerpo pero ya se puede hablar y mover la cabeza.












- ActorImpl:


package es.historia.mueve.impl;

import es.historia.IActor;
import es.historia.ICabeza;
import es.historia.ICuerpo;
import javafx.scene.Group;

import javafx.scene.media.MediaPlayer;
import javafx.scene.media.Media;
import javafx.util.Duration;



/**
*
* @author Propietario
*/
public class ActorImpl implements IActor {
private ICabeza cabeza;
private ICuerpo cuerpo;
@Override
public Group dibujar() {
Group salida =new Group();
if (cabeza != null){
salida.getChildren().add(cabeza.dibujar());
cabeza.empezarMovimientoFijo();
}
if (cuerpo != null)
salida.getChildren().add(cuerpo.dibujar());
return salida;
}

@Override
public void mover() {
if (cabeza!= null)
cabeza.mover();
}

@Override
public void definir(ICabeza cabeza, ICuerpo cuerpo) {
this.cabeza = cabeza;
this.cuerpo= cuerpo;
}

@Override
public void hablar(String frase , final ICabeza cabeza) {
final MediaPlayer player = new MediaPlayer(new Media( frase));
player.play();
cabeza.empiezaHablar();
player.seek(Duration.ZERO);
player.setOnEndOfMedia(new Runnable() {

@Override
public void run() {
cabeza.terminaHablar();
}
});
}

@Override
public void establecerPosicion(int i, int i0) {
throw new UnsupportedOperationException("Not supported yet.");
}

Es esta clase podemos ver la funcionalidad de reproducir audio. Lo mas destacable del objeto MediaPlayer es que nos permite lanzar un hilo con una funcionalidad al "suceder" uno de los siguientes eventos:












- CabezaImpl:

package es.historia.parte.impl;

import es.historia.HistoriaExcepcion;
import es.historia.ICabeza;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.scene.Group;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.transform.Affine;
import javafx.util.Duration;

/**
*
* @author Propietario
*/
public class CabezaImpl implements ICabeza{
private Timeline timelineTodo;
private Timeline timelineBoca;
private ImageView visorParteSuperior;
private ImageView visorParteInferior;

@Override
public void establecerCara(String caraInferior, String caraSuperior) throws HistoriaExcepcion {
Image imagen1 = new Image(caraSuperior);
if (imagen1 == null || imagen1.isError())
throw new HistoriaExcepcion("La imagen " + caraSuperior + " no es accesible");
Image imagen2 = new Image(caraInferior);
if (imagen2 == null || imagen2.isError())
throw new HistoriaExcepcion("La imagen " + caraInferior + " no es accesible");
visorParteSuperior= new ImageView (imagen1);
visorParteInferior= new ImageView (imagen2);
}

@Override
public Group dibujar() {
Group salida =new Group();
salida.getChildren().add(visorParteSuperior);
salida.getChildren().add(visorParteInferior);
return salida;
}

@Override
public void mover() {
}

@Override
public void establecerPosicion(int x, int y) {
visorParteInferior.setLayoutX(x);
visorParteInferior.setLayoutY(y + visorParteSuperior.getImage().getHeight());
visorParteSuperior.setLayoutX(x);
visorParteSuperior.setLayoutY(y);
}

@Override
public void empezarMovimientoFijo() {
timelineTodo = new Timeline();
timelineTodo.setCycleCount(Timeline.INDEFINITE);
timelineTodo.setAutoReverse(true);
final Affine reflectTransform = new Affine();
//
visorParteSuperior.getTransforms().add(reflectTransform);
visorParteInferior.getTransforms().add(reflectTransform);
timelineTodo.getKeyFrames().addAll(new KeyFrame(Duration.ZERO,
new KeyValue(reflectTransform.mxxProperty(), -1, Interpolator.DISCRETE),
new KeyValue(reflectTransform.txProperty(), visorParteSuperior.getBoundsInLocal().getWidth(),
Interpolator.DISCRETE)
),
new KeyFrame(new Duration(2000L),
new KeyValue(reflectTransform.mxxProperty(), 1, Interpolator.DISCRETE),
new KeyValue(reflectTransform.txProperty(), 0, Interpolator.DISCRETE)),
new KeyFrame(new Duration(4000L),
new KeyValue(reflectTransform.mxxProperty(), -1, Interpolator.DISCRETE),
new KeyValue(reflectTransform.txProperty(), visorParteSuperior.getBoundsInLocal().getWidth(),
Interpolator.DISCRETE)
));
timelineTodo.play();
}

@Override
public void empiezaHablar() {
timelineBoca = new Timeline();
timelineBoca.setCycleCount(Timeline.INDEFINITE);
timelineBoca.setAutoReverse(true);
timelineBoca.getKeyFrames().addAll(new KeyFrame(Duration.ZERO,
new KeyValue(visorParteInferior.rotateProperty(), 40, Interpolator.DISCRETE),
new KeyValue(visorParteInferior.translateYProperty(), 30, Interpolator.DISCRETE)),
new KeyFrame(new Duration(100L),
new KeyValue(visorParteInferior.rotateProperty(), 0, Interpolator.DISCRETE),
new KeyValue(visorParteInferior.translateYProperty(), 0, Interpolator.DISCRETE)),
new KeyFrame(new Duration(200L),
new KeyValue(visorParteInferior.rotateProperty(), -40, Interpolator.DISCRETE),
new KeyValue(visorParteInferior.translateYProperty(), 30, Interpolator.DISCRETE)),
new KeyFrame(new Duration(300L),
new KeyValue(visorParteInferior.rotateProperty(), 0, Interpolator.DISCRETE),
new KeyValue(visorParteInferior.translateYProperty(), 0, Interpolator.DISCRETE)));

timelineBoca.play();
}

@Override
public void terminaHablar() {
timelineBoca.stop();
visorParteInferior.setRotate(0);
visorParteInferior.setTranslateY(0);
}

}

Lo mas destable es:

  • Se utilizan dos linas de tiempo. Una que no para nunca que cambia la orientacion de la cabeza y otra que solo funciona cuando se esta hablando y mueve la boca.
  • Las transformaciones. Siempre que se pueda se debe utilizar una propiedad (como setRotate) pero su la transformacion que se desea no se puede conseguir con una funcion que ofrece la clase entonces se puede usar transformaciones en forma de matriz(Affine).

viernes, 16 de marzo de 2012

JavaFX 2.0. Vamos a crear una historia. Parte I

Swing es una tecnología fácil y rápida para crear una interfaz grafica de una aplicación. En mi modesta opinión, JavaFX 2.0 ofrece la posibilidad de dar mas potencia a las interfaces graficas que puede ofrecer la tecnología Java. A JavaFX 2.0 lo único que le falta es tiempo de “incrustarse” en el uso cotidiano de los programadores.

Voy a explicar un framework muy sencillo para crear una historia con muñecos. Todo con JavaFX2.0. La idea es que busques una cara que quieres animar, como por ejemplo la de nuestro amigo George:















Recartar la cara con cualquier programa de edicion de imagenes, cortarla en dos partes (superior e inferior) y animarla poniendole voz:









En esta primera parte voy a centrarme en las interfaces; las implementaciones en el siguiente post.

El proyecto lo he creado con Netbeans 7.1. Se debe crear la siguiente estructura de clases:


















La idea es que en una clase donde se quiere crear una "historia" se debe crear actores que se componen de cuerpo y de cabeza.


- Main.java: Punto de entrada de la aplicación.

package es;

import es.historia.HistoriaExcepcion;
import es.historia.IActor;
import es.historia.ICabeza;
import es.historia.mueve.impl.ActorImpl;
import es.historia.parte.impl.CabezaImpl;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;

/**
*
* @author Propietario
*/
public class Main extends Application {

/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws HistoriaExcepcion {
primaryStage.setTitle("Dibujo!");

// Se crea el actor
final IActor juguete = new ActorImpl();

// Se crea la cabeza
final ICabeza cabeza= new CabezaImpl();

// imagen que es la parte superior e inferior de la cabeza
cabeza.establecerCara("c:/caraInferior.JPG", "c:/caraSuperior.JPG");

// donde ponerlo dentro de la pantalla
cabeza.establecerPosicion(50,50);

// se define la cabeza del actor. El cuerpo para otro post.
juguete.definir(cabeza, null);

// Un boton para que hable
Button btn = new Button("Hablar");
btn.setOnAction(new EventHandler(){

public void handle(ActionEvent event) {

juguete.hablar("file:/uno_comoestas.wav", cabeza);
}

});


// un actor dibujado no es mas que un grupo de componentes JavaFx 2.0
Group group = juguete.dibujar();
group.getChildren().add(btn);

// apartir de aqui ya es como cualquier otra aplicacion JavaFx 2.0
Scene scene = new Scene(group, 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
}
}

- HistoriaExcepcion: Excepcion para el uso dentro del framework

package es.historia;

/**
*
* @author Propietario
*/
public class HistoriaExcepcion extends Exception{

public HistoriaExcepcion(String string) {
super(string);
}
}

package es.historia;

- IActor: Requerimientos de una clase que sea una implementacion de un actor.

/**
*
* @author Propietario
*/
public interface IActor extends IMovimiento{
// Un actor es siempre una cabeza y un cuerpo
public void definir(ICabeza cabeza, ICuerpo cuerpo);
// accion de hablar
public void hablar(String frase,final ICabeza cabeza);
}

- ICabeza: Requerimientos de una clase que sea una implementacion de una cabeza.


package es.historia;

/**
*
* @author Propietario
*/
public interface ICabeza extends IMovimiento{
//una cara es una imagen superio y una cara inferior
public void establecerCara (String caraInferior, String caraSuperior) throws HistoriaExcepcion;

// definir posicion
public void establecerPosicion(int i, int i0);

// movimiento que se sucede siempre
public void empezarMovimientoFijo();

//movimiento cuando se habla
public void empiezaHablar();

// movimiento cuando se termina de hablar
public void terminaHablar();
}
- ICuerpo: Requerimientos de una clase que sea una implementacion de un cuerpo.

package es.historia;

/**
*
* @author Propietario
*/
public interface ICuerpo extends IMovimiento{
}

- IMarco: Requerimientos de una clase que sea una implementacion de un cuerpo.
package es.historia;

/**
*
* @author Propietario
*/
public interface IMarco {
}


- IMovimiento: Que funcionalidad debe de tener implementaciones que se puedan mover (cabeza, cuerpo, actor, etc..)
package es.historia;

import javafx.scene.Group;

/**
*
* @author Propietario
*/
public interface IMovimiento {
// dibujar la unidad (cuerpo, cabeza, etc..)
public Group dibujar ();
// mover la unidad
public void mover();
}