Archivos del sitio
No me funciona Java Web Start en Opera
Java Web Start es una tecnología muy de moda (en Viavansi imprescindible, ya me entendeís). Puede ocurrir que no tengaís bien configurado el navegador o que por error cuando lanzaís un jnlp pulseís “Guardar” y estuviera marcada la casilla “Recordar esta acción” (no señalo con el dedo quién puede cometer semejante muñonada).
Pues no desesperes, lo único que debes hacer es reestablecer el tipo Mime del navegador y todo arreglado. En el caso de Opera:
Herramientas -> Preferencias -> Avanzado -> Descargas
MIME Type: application/x-java-jnlp-file
File Extension: jnlp
Action: Open with default application
Reinicia navegador y listo. Esto es válido para cualquier navegador en su zona de tipos Mime. Obviamente deberás tener instalado el intérprete de JWS (el propio JDK lo trae).
Puntero del ratón en VNC
VNC es una herramienta impresionante para controlar remotamente un PC. Sin embargo una de las cosas más molestas que tiene es que si la máquina destino no tiene enchufado un ratón en lugar de aparecerte la típica flecha te aparece un insignificante cuadradito haciendo las veces de ratón cuando controlas ese PC en remoto.
Como enchufar un ratón a cada una de las máquinas remotas es un engorro (y además no tiene sentido enchufarle algo que no vas a usar), existe otra alternativa mucho más práctica, al menos si es un Windows, y consiste en activar las mouse keys en el PC remoto:
Panel de Control -> Opciones de accesibilidad -> Mouse Keys (activar)
Con esto se supone que el keypad simularía el ratón en la máquina remota, y el resultado es que tendremos el puntero del ratón en el VNC, cosa que se agradece.
El que encuentre la forma de tener puntero en Linux se lleva un gallifante de premio :-).
Sun’s RI for JSF vs MyFaces
Época de despedidas, hoy le toca el turno a MyFaces
Después de más de dos años utilizando la implementación Apache Myfaces JSF, ha llegado el momento de las despedidas, en adelante todos nuestros proyectos se pasan a la implementación JSF 1.2 de Sun. No existe un motivo principal, pero si muchos pequeños problemas que finalmente nos han hecho decidirnos por la migración. Sin intención de entrar en detalle, estas son las motivaciones principales:
- En el momento de tomar la decisión, la implementación de Sun de la especificación 1.2 era mucho mas madura que la de Myfaces. En las pruebas realizadas pudimos comprobar que el numero de bugs es mucho mayor en la implementación Myfaces. En general Sun’s RI es una implementación mucho mas pulida.
- El número de incompatibilidades que hemos sufrido al migrar de la especificación 1.1 a 1.2 ha sido mucho menor con la implementación de Sun.
- Es posible seguir utilizando las librerías Tomahawk con la implementación de Sun.
- La implementación de Sun parece ofrecer mejor rendimiento que la implementación de Myfaces.
- La integración con Seam es mucho mas sencilla utilizando la implementación de Sun.
- Gracias a la filosofía una especificación, múltiples implementaciones; el cambio era posible.
Algunos libros de programación y su consorte
No están todos los que son, pero si son todos los que están:
- Programación Java Server con J2EE Edición 1.3.
- Desarrollo Web JSP.
- XML.
- Hackers de Java y J2EE.
- Core JavaServer Faces.
- Core Java2.
- Pro Apache XML.
- Patrones de diseño aplicados a Java.
- Pro J2EE 1.4.
- OpenGL.
- Java Portlet API.
- Pro Apache.
- Java Criptography Extensions.
- Subversion Version Control.
- Programación con ASP.NET 2.0.
- UML2.
- Cryptography with Java.
- Beautiful Core.
- Oracle 9.
- SOA.
- Pro JSF and Ajax.
- Inteligencia Artificial, Un Enfoque Moderno.
- Java EE 5.
- Por EJB 3, Java Persistence API.
- SOA Using Java Web Services.
- JBoss Seam.
- Spring MVC and Web Flow.
- Core Java SE 6
- El Yermo de Aiel ( La Rueda del Tiempo)
- La danza de la Realidad de Alejandro Jodorowsky.
- Usabilidad.
- Flow.
- La Mente de Dios.
- Gödel, Escher, Bash, Un eterno y grácil bucle.
Una JSF universal
Un ejemplo de como simplificarnos la vida usando nuestras propias annotations.
Por la razon que fuese teniamos que crearnos un numero considerable pero finito de VOs con un numero tendiente a infinito de propiedades. Estos VOs a los que llamaremos FooData1VO, FooData2VO, … FooDataNVO; estos VOs , digo, iban a ser usados en JSFs en los que una lista del mismo FooDataXVO se representaria como una tabla, una tabla que a su vez seria exportable a excel.
Bien, tenemos dos formas de hacerlo. La normal o infernal, y la anotada o elegante y facil.
En la normal, nos creamos N VOs, N Controllers, y N JSFs.
En la version anotada que proponemos aqui necesitamos: N+1 VOs, 1 Controller universal, 1 JSF universal y 1 Annotation.
Lo primero que hacemos es crearnos nuestra anotacion java (annotation).
Para mas informacion sobre que y como y porque, os remito a mis ya viejos articulos Tu primera annotation chipas I y II:
http://xnoccio.com/62-tu-primera-annotation-chispas-i/
http://xnoccio.com/72-tu-primera-annotation-chispas-ii/
package com.viavansi.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.ElementType;
/**
* @author dbejar
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface WiseName{
String alias();
}
Este es un caso muy sencillito en el que unicamente le damos un nombre en lenguaje natural a una propiedad. Podriamos como en el caso real en el que desarrollamos esto, añadirle un booleano para distinguir entre propiedades exportables a excel, o un enum para hacer subconjuntos dentro del mismo VO. Pero estoy adelantando cosas…
A continuacion nos creamos una clase padre de nuestros VOs:
package com.viavansi.VO;
import java.lang.reflect.Field;
import com.viavansi.annotation.WiseName;
public abstract class FooDataSuperVO{
/**
* Devuelve una lista ordenada con todos los labels de los atributos marcados
* con la annotation WiseName
* @return
*/
public List<String>getWiseNamedLabels(){
List<String>aliases=new LinkedList<String>();
for (Field field : this.getClass().getDeclaredFields()){
WiseName nombreBonito=field.getAnnotation(WiseName.class);
if (nombreBonito==null) continue;
aliases.add(nombreBonito.alias());
}
return aliases;
}
/**
* Devuelve una lista ordenada con todos los nombres de los atributos marcados
* con la annotation WiseName
* @return
*/
public List<String> getWiseNamedProperties(){
List<String>propNames=new LinkedList<String>();
for (Field field : this.getClass().getDeclaredFields()){
WiseName nombreBonito=field.getAnnotation(WiseName.class);
if (nombreBonito==null) continue;
propNames.add(field.getName());
}
return propNames;
}
No requiere mucha explicacion, si se han leido y entendido mis articulos sobre Annotation. Basicamente con esas dos funciones por reflection obtenemos en una todas las propiedades anotadas, y en la otra el valor de la propiedad alias en esas anotaciones.
Ahora un ejemplo muy muy simple de uno de los VOs anotados:
package com.viavansi.VO;
public class FooData1VO extends FooDataSuperVO{
@NombreBonito(alias="1. Terrenos y bienes naturales")
private Double balActInmInvTerrYBienNat;
@NombreBonito(alias="2. Infraestructuras y bienes destinados al uso general")
private Double balActInmInvInfYVBienUsoGral;
//etc..
//Con sus geterts y setters
}
Ya estamos terminando.
Con estas anotaciones solo necesitamos una JSF. Una para todos los VOs. Y un unico controller tambien.
En el Controller introducimos un par de getters de la siguiente pinta:
/**
* Devuelve una lista ordenada con todos los nombres de los atributos marcados
* con la annotation WiseName
* @author cvillar,dbejar
*@return
*/
public List<String> getListNombresBonitosProperties(){
if (listaPaginas.getRegistros().get(0) instanceof FooData1VO){
return new FooData1VO().getWiseNamedProperties();
}else if (listaPaginas.getRegistros().get(0) instanceof FooData2VO){
return new FooData2VO().getWiseNamedProperties();
}//else if [....]
//N veces
}else if (listaPaginas.getRegistros().get(0) instanceof FooDataNVO){
return new FooDataNVO().getWiseNamedProperties();
}else{
log.error("Primer registro de listaPaginas no es de un tipo VO implementado");
return new LinkedList<String>();
}
}
/**
* Devuelve una lista ordenada con todos los labels de los atributos marcados
* con la annotation WiseNamed
* @author cvillar,dbejar
*@return
*/
public List<String> getListWiseNamedLabels(){
//Trivial. La misma idea que el metodo anterior.
}
Y finalmente nuestra JSF universal y super simplificada:
<v:dataTable id="data" var="fila" styleClass="display_table" controller="#{FooDataController}">
<c:forEach var="propiedad" items="#{FooDataController.listWiseNamedProperties}" varStatus="rowCounter">
<v:column property="#{propiedad}" label="${FooDataController.listWiseNamedLabels [rowCounter.index]} "/>
</c:forEach>
</v:dataTable>
Hala pues,
¡Eclipse no me autocompleta!
¿A quién no le ha sucedido alguna vez que Eclipse deja de autocompletar los códigos fuente en Java por arte de magia? Sin haber tocado nada y sin causa aparente, arrancas Eclipse tranquilamente y donde ayer completaba un .java normal y corriente hoy no. La solución es más simple de lo que crees:
Window -> Preferences -> Java -> Editor -> Content Assist -> Advanced
Al llegar aquí lo más probable es que tengas desmarcadas todas las opciones. Pues haz un “Restore Defaults” y verás que se marcan varias opciones. Ahora sí debería autocompletar.
Los créditos por esta aportación van al señor Rubén Quintero.
Desarrollando un plugin Maven Report (I)
Hace varios meses me enfrenté al primer desarrollo de un plugin Maven para generar un report en el site, y comprobé en mis carnes que había muy muy poca documentación, y en castellano era totalmente inexistente. Por ello considero interesante describir paso a paso el proceso para desarrollar un plugin sencillo del tipo Hola Mundo!, dejando para un post futuro otros detalles interesantes, como la utilización de ficheros properties, introducción de parámetros de configuración, generación de ficheros externos al report, etc.
Este post supone que el lector ya está suficientemente familiarizado con la utilización de Maven, por lo que no entraré en detalles excesivamente básicos, como explicar lo que es un pom.xml, cómo se utiliza Maven, etc. Lo único básico que explicaré es que un plugin Maven Report sirve para generar un informe que se anexa al site del proyecto (se invoca, por ejemplo, ejecutando ‘mvn site’) siempre que esté referenciado en el pom.xml del proyecto llamante, dentro de <reporting><plugins>. El propio site de Maven ya embebe varios plugins Report como el de dependencias.
Con esta sencilla introducción, vamos al lío: lo primero, un plugin report es un proyecto Maven, por lo que tiene su pom.xml y su directorio /src/main/java. Veamos cómo sería nuestro pom.xml:
<?xml version="1.0" encoding="UTF-8"?><project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.viavansi</groupId>
<artifactId>report-plugin-demo</artifactId>
<packaging>maven-plugin</packaging>
<version>0.0.1</version>
<name>Plugin demo Report</name>
<inceptionYear>2008</inceptionYear>
<url>http://www.viavansi.com</url>
<organization>
<name>Servicios Avanzados para las Instituciones S.L. (VIAVANSI )</name>
<url>http://www.viavansi.com</url>
</organization>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-project</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven.reporting</groupId>
<artifactId>maven-reporting-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven.reporting</groupId>
<artifactId>maven-reporting-impl</artifactId>
<version>2.0.2</version>
</dependency>
</dependencies>
</project>
He marcado en negrita los puntos clave: por un lado, debemos indicarle a Maven que este proyecto es un plugin mediante la etiqueta <packaging>, y además declaramos las dependencias a los APIs de construcción de plugins y reporting de Maven.
Una vez creado nuestro fichero pom.xml, estamos en disposición de crear la clase del plugin en el paquete que deseemos, obviamente dentro de /src/main/java.
Un plugin report debe extender de la clase org.apache.maven.reporting.AbstractMavenReport, lo cual obliga a sobrescribir los siguientes métodos:
- protected String getOutputDirectory(): devuelve el directorio donde se generará el fichero HTML del report
- protected MavenProject getProject(): devuelve una referencia objetual al pom.xml del proyecto padre que llama al report
- protected Renderer getSiteRenderer(): devuelve la instancia del objeto que rendea el site Maven
- public String getDescription(Locale locale): devuelve la descripción del plugin, permitiendo internacionalización en función del Locale.
- public String getName(Locale locale): devuelve el nombre del plugin, permitiendo internacionalización en función del Locale.
- public String getOutputName(): devuelve el nombre del fichero HTML que se va a generar.
- protected void executeReport(Locale locale): esta es la madre del cordero, es el método que se invoca para generar el informe.
Para implementar los 3 primeros métodos, es interesante saber que Maven entregará a nuestra clase 3 objetos:
- Una instancia de Renderer
- Una instancia de MavenProject
- Una instancia de File, que se corresponde con el directorio de salida por defecto (el /target/site)
De forma que los utilizaremos para implementar esos 3 métodos. Para que Maven nos entregue esas 3 instancias, deberemos declarar esos 3 atributos de la clase y utilizar Annotations. Veremos esto al incluir el código entero de la clase.
Otro punto clave es que es obligatorio incluir un goal Maven a cada plugin, con una anotación @goal.
Y un último concepto de importancia es cómo escribir el HTML. Para ello se hace uso del API Sink perteneciente al proyecto Doxia. Utilizando el método getSink() obtenemos el objeto Sink que nos permite escribir información al informe.
Veamos el código Java del plugin. He marcado en negrita algunas de las líneas clave, siguiendo las instrucciones que he comentado anteriormente. El código está comentado para explicar paso por paso lo que es está haciendo:
package com.viavansi.maven.report;
import java.io.File;
import java.util.Locale;
import org.apache.maven.doxia.siterenderer.Renderer;
import org.apache.maven.project.MavenProject;
import org.apache.maven.reporting.AbstractMavenReport;
import org.apache.maven.reporting.MavenReportException;
import org.codehaus.doxia.sink.Sink;
/**
* Genera un Hola Mundo en un site
* @goal demo
*/
public class DemoMojo extends AbstractMavenReport {
/**
* Directorio donde se generará este report
*
* @parameter expression="${project.reporting.outputDirectory}"
* @required
*/
private File outputDirectory;
/**
* Maven nos pasa este valor, no debemos configurarlo.
*
* @component
*/
private Renderer siteRenderer;
/**
* Instancia del proyecto (pom) que nos llamará.
* De aquí se puede sacar cualquier información del pom.
*
* Maven nos pasa este valor, no debemos configurarlo.
*
* @parameter expression="${project}"
* @required
* @readonly
*/
private MavenProject project;
@Override
protected String getOutputDirectory() {
return this.outputDirectory.getAbsolutePath();
}
@Override
protected MavenProject getProject() {
return this.project;
}
@Override
protected Renderer getSiteRenderer() {
return this.siteRenderer;
}
public String getDescription(Locale locale) {
return "Nuestro primer plugin Maven Report";
}
public String getName(Locale locale) {
return "DemoMavenReport";
}
public String getOutputName() {
return "demo";
}
@Override
protected void executeReport(Locale locale) throws MavenReportException {
//Ejemplo de log en consola
getLog().info("Iniciando plugin Demo");
//Hago las tareas que deba hacer, lo lógico sería delegar la responsabilidad
//Recupero el API Sink de Doxia para "pintar" resultados
Sink sink = (Sink)getSink();
//Cabecera del report
sink.head();
sink.title();
sink.text("Nuestro primer Report Maven");
sink.title_();
sink.head_(); //Se cierran las maquetaciones de forma similar a HTML
//Cuerpo del report
sink.body();
sink.section1();
sink.sectionTitle1();
sink.text( "Apartado 1" );
sink.sectionTitle1_();
sink.paragraph();
sink.text("Hola Mundo!");
sink.lineBreak();
//Ejemplo de utilización de información del pom del proyecto que llama
sink.text("Detectamos en el pom: "
+project.getGroupId()+"."+project.getArtifactId()+"-"+project.getVersion());
sink.paragraph_();
sink.section1_();
sink.body_();
}
}
Y listo. Para probar nuestro plugin, simplemente podríamos instalarlo en nuestro repositorio local (mvn install) o desplegarlo en algún repositorio de librerías, y referenciarlo desde otro proyecto Maven, en el apartado <reporting><plugins>…</plugins></reporting>. Veremos cómo se agregará nuestro report al site generado.
En un siguiente post mostraremos cómo podemos añadir características avanzadas a nuestros reports. Hasta entonces, feliz año a todos.
El falso Santo Grial de J2EE y la nueva esperanza JEE
Con visión retrospectiva podemos ver que muchas de las bases sobre las que se sustentaba J2EE fueron un error.
En los primeros días de J2EE, los xmls eran vistos como el Santo Grial de la configuración, el framework estaba pensado para que todo se pudiera y tuviese que configurar en un xml, incluyendo nombres de clases java y métodos. Esta técnica que sobre el papel parecía ideal para ayudar al desacoplamiento del sistemas tenía consecuencias nefastas en el desarrollo.
La configuración en ficheros xml resultó ser muy repetitiva, propensa a errores (muy difíciles de encontrar en tiempo de ejecución) y en definitiva demasiado compleja para el programador medio.
Ahora, mirando hacia atrás podemos ver que no solo el propio J2EE, sino también otros frameworks como Hibernate, Struts, Spring, iBatis, etc… cometieron el mismo error, y poco a poco la plataforma Java se ha ido haciendo cada vez más y más compleja, hasta ser considerada por algunos como un dinosaurio inmanejable, con una dura curva de aprendizaje.
Esta situación, conocida como “El infierno XML“, la han aprovechado muy bien otros lenguajes como Ruby on Rails con su lema programación por convención, que precisamente evita la trampa en la que cayó J2EE.
Por suerte la comunidad Java ha reconocido el problema del abuso de XMLs y ha actuado remplazando parcialmente los ficheros XML con una mezcla de anotaciones en el código y convenciones establecidas que sólo requieren la configuración de los casos excepcionales.
Como respuesta a estos y otros problemas, han empezado a aparecer algunas soluciones como por ejemplo:
* EJB3/JPA: Que simplifica dramáticamente el engorro que actualmente suponía trabajar con EJBs 2.0 o Hibernate y que desde hace un año forma parte de todas nuestras aplicaciones con unos resultados excelentes.
* Seam: Un framework ligero para Java EE 5.0 que simplifica el desarrollo de aplicaciones web y que despues de algunos proyectos internos, se convierte este año 2008 en nuestro framework base para todos nuestros nuevos proyectos web.
* Web Beans (JSR 299): La gran esperanza que parte del camino iniciado por Seam y que pretende convertirse, al igual que ya pasó con JPA, en el estándar para comunicar la capa web con los EJBs.
* Grails: Que ha resultado muy ilusionate en las pruebas y quizás en el futuro se convierta tambien en compañero de viaje.
* JAX-WS 2.x: Que simplifica enormemente tanto la publicación como el consumo de Servicios Web. Después de años utilizando Axis, JAX-WS pasa a convertirse en nuestra pila Web services preferida.
En definitiva, aunque los XMLs seguiran siendo parte esencial de nuestro día a día, un nuevo camino se abre en los paradigmas de programación Java, …
Busca esto rápido
Encuentra lo que buscas de forma sencilla usando el buscador.
Categorías
Encuentra artículos a través de sus "tags"
Archivos mensuales
Encuentra artículos según el mes en el que fueron escritos.
