miércoles, 7 febrero 2007

Apuntes maven2

Consultar versi'on que est'a usando de un plugin
mvn help:describe -DgroupId=org.apache.maven.plugins -DartifactId=maven-site-plugin
Posted by angel at 10:57 AM in Java

miércoles, 19 julio 2006

ant javac OutOfMemory

Al ejecutar un ant que genera un war, en el momento de compilar los jsps me da un error de memoria.
¿Cómo asiganr más memoria al proceso del ant?
Pues, el proceso es tan sencillo como en el resto de las aplicaciones java:
ANT_OPTS="-Xms512m -Xmx512m" ant WarProduccion
Posted by angel at 6:44 PM in Java

viernes, 16 junio 2006

Dejando bonitas las fuentes

Me refiero a dejar bonitas las fuentes de las aplicaciones Java, por supuesto.
Voy a lista aquí una serie de utilizades que he econtrado para este menester:
  • Checkstyle.- Parece bueno Checkstyle is a development tool to help programmers write Java code that adheres to a coding standard.
  • Artistic Style.- Sólo indenta
  • ImportScrubber.- Organizador de imports.
    Tiene limitaciones muy gordas: Ver
  • Jacobe.-
  • JCSC.- Muchos chequeos distintos.
  • PMD.- Parece bueno. PMD scans Java source code and looks for potential problems.
  • Jlint.- El autor dice que es muy rapido, y no me estraña. Está hecho en C.
    Jlint will check your Java code and find bugs, inconsistencies and synchronization problems
  • Ick.- Import management tool for Java programs written in Java.
    Sencillo, pero hace su labor.
En cuanto los tenga probados comento algo.
Posted by angel at 5:14 PM in Java

miércoles, 6 julio 2005

UTF-8, tomcat 5.0.28 y aplicaciones web

UTF-8 en aplicaciones web.

Planteando el problema.

Tras actualziar todas las máquinas a UTF8, tanto en las que desarrollo como en los servidores, me dispongo a pasar las aplicaciones web también a utf8.
En un principio parecía tan sencillo como poner la cabecera <%@ page language="java" contentType="text/html; charset=utf-8"%> a todos los jsp.
Debido a que los sistemas están configurados con UTF8, la máquina java que levanta el tomcat también usa utf8, así como el MySQL y demás aplicaciones.

Todo parece que va bien, pero ..... Intento insertar en la base de datos y los caracteres acentuados me los inserta mal (Caracteres raros).
Lo primero que puenso es que la base de datos está usando Latin1 y se le envía datos en utf8, pero no es así. Resulta que los datos que recupero mediante request.getParameter(..) ya contienen esos caracteres raros.
Es decir, el problema reside en la comunicación entre el cliente y el servidor. Será que el cliente no envía bien los datos, o será que el servidor no los recoge bien.
Tras buscar y buscar en internet, probar soluciones de todo tipo (gracias, Alfredo) me encuentro lo que parece ser el origen del problema, pero no la solución.
Parece ser cuando se envía la información por post, el servidor de aplicaciones es incapaz de enterarse qué codificación está usando el navegador.

Entorno.

Linux Gentoo
Tomcat 5.0.28
Sun JDK 1.4.2.08

Solución.

Teniendo acotado el problema, me dispongo a buscar por internet (el google siempre es nuestro primer recurso) y encuentro soluciones de todo tipo.
Existe gente que incluso opta por indicar el encode cada vez que recupera un valor del request. Imaginaros cómo se complica el código.

Los pasos que yo he seguido para que (por lo menos aparentemente, el tiempo lo dirá) funcione todo con UTF8 son los siguiente:

  • En cada jsp indico la codificación para el mismo mediante:
    <%@ page language="java" contentType="text/html; charset=utf-8"%>
    
  • Configuro el tomcat para que la uri la decodifique también con utf8. Dentro de la uri entran los parámetros pasados por get.
    Para ello modifico el Connector del servlet.xml. Por ejemplo:
        <Connector acceptCount="100" connectionTimeout="20000"
    	disableUploadTimeout="true" port="8080" redirectPort="8443" maxSpareThreads="75"
    	maxThreads="150" minSpareThreads="25" URIEncoding="UTF-8">
        </Connector>
    
    Lo importante es el URIEncoding="UTF-8"
  • Y por último, pero no menos importante: Meto un filtro para indicar que si no se especifica la codificación para el request, se use utf8.
    Para ello me creo el Filtro:
    package com.acervera.commons.filtros;
    
    import java.io.IOException;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    
    public class UTF8Filter implements Filter {
    
    	public void init(FilterConfig config) throws ServletException {
    
    	}
    
    	public void doFilter(ServletRequest request,
    			ServletResponse response,
    			FilterChain chain) throws IOException, ServletException {
    		// Si no se especificar el encoding, le indicamos que use el utf-8. De lo contrario, usaría el iso-8859-1
    		if(request.getCharacterEncoding()==null) {
    			request.setCharacterEncoding("utf-8");
    		}
    		chain.doFilter(request,response);
    
    	}
    
    	public void destroy() {
    	}
    
    }
    
    Lo instalo en el web.xml asegurándome que es el primero de todos en ejecutarse (Es decir, lo mapeo el primero):
    <web-app >
    	<filter>
    		<filter-name>UTF8Filter</filter-name>
    		<filter-class>com.acervera.commons.filtros.UTF8Filter</filter-class>
    	</filter>
    	.............
    	<filter-mapping>
    		<filter-name>UTF8Filter</filter-name>
    		<url-pattern>/*</url-pattern>
    	</filter-mapping>
    	.............
    </web-app>
    

Posted by angel at 12:48 PM in Java

jueves, 21 julio 2005

Tratamiento de imagenes.

Un link muy interesante sobre la nueva forma de tratar las imágenes a partir de la versión 1.4 del jdk:
http://java.sun.com/developer/JDCTechTips/2004/tt0217.html
http://java.sun.com/j2se/1.4.2/docs/guide/imageio/spec/title.fm.html
http://weblogs.java.net/blog/chet/archive/2004/07/imageio_just_an.html
Próximamente, cómo?
Posted by angel at 10:49 PM in Java

sábado, 23 julio 2005

Struts - Forward con parámetros.

Problema:

Desde los inicios de los tiempos, struts ha tenido un problema en los forward.
En la deficinición del forward, dentros del struts-config.xml, no se podían indicar parámetros.
El problema se complicaba cuando estos parámetros son dinámicos (que es la mayoría de los casos).

Solución.

A partir de la versión 1.2.7 parece que se ha arregado el problema.
Existe una clase nueva que herada del ActionForward.
Se trata de ActionRedirect.
En el javadoc se puede ver cómo funciona, pero baśicamente:
  • Declaramos el forward en el struts-config.xml, sin parámetros.
    <action ............ >
    	<forward name="elForward" path="/loquesea.jsp" />
    	<forward name="elForward2" path="/loquesea.do" />
    </action>
    
  • En la implementación de nuestro Action, obtenemos el ActionForward que hemos declarado anteriormente.
    ForwardConfig forwardConfig = mapping.findForward("elForward");
    
  • A partir del ActionForward anterior, creamos el ActionRedirect, pasándole los parámetros que necesitemos.
    ActionRedirect redirect = new ActionRedirect(forwardConfig);
    redirect.addParameter("param1","value1");
    redirect.addParameter("param2","2");
    redirect.addParameter("param3","3.0");
    return redirect;
    
Posted by angel at 11:28 AM in Java

domingo, 25 septiembre 2005

Bugs Validación en Struts y Commons Validator

Me he encontrado con un problema curioso que existe desde siempre.
Resulta que las aplicaciones que desarrollamos siempre metemos la posibilidad de I18N y L10N.
Hasta ahora todo parecía ir bien, pero resulta que cuando mostramos un valor numérido, por costumbre, lo formateamos para una buena comprensión del usuario (es decir, metemos la coma de decimales y demás).
Resulta que cuando se formatea se usa la configuración del Locale seleccionado en el navegador, donde nos indica cuál es el separador decimal.
Pues cual es mi sorpresa cuando me doy cuenta que los usuarios de las aplicaciones tienen que estar usando como separador decimal el punto, ya que el commons-validator y el framework de validación de struts (el primero por no estar implementado y el segundo porque usa el primero) pasa olímpicamente de la localización del usuario.
Tras buscar he encontrado estos dos bugs en el bugzilla.
  • Validator: http://issues.apache.org/bugzilla/show_bug.cgi?id=16249
  • Struts: http://issues.apache.org/bugzilla/show_bug.cgi?id=21282
Pues la solución que me he currado (hasta que lo arreglen en próximas release de los dos productos) la podéis bajar de aquí.
Los comentarios los podéis encontrar en el javadoc de la clase (es decir, en el código).
Está basado en los parches facilitados en los dos bugs y alguna modificación / añadido propio, para no tener que modificar el código original del strusts ni del commons-validator.

Un saludo a todos.
Posted by angel at 5:23 AM in Java

lunes, 4 julio 2005

Implementación de Realm.

Implementación de Realm para casos particulares.

Planteando el problema.

Aplicación tras aplicación web, me encuentro con el mismo problema de autentificación y autorización.
Hasta el día de hoy me he ido adaptando a los dos sistemas estándar de autentificación que vienen suministrado por Tomcat.
Pero el problema precisamente es ese, que yo me tengo que adaptar a ello, pero no hay manera de adaptarlos a mis necesidades.
Los dos sistemas de los que hablo son DataSourceRealm y JDBCRealm.
¿Cuál es el problema con el que me encuentro en dos sistemas? Pues que el campo usuario se tiene que llamar igual en la tabla con los datos del usuario y en la tabla con la lista de roles, además de tener que estar relacionados con ellos.
Resulta que mediante este sistema estás “casi” obligado a que la clave del usuario sea la misma que el código del usuario para hacer login.
La estructura de mi base de datos es muy distinta, ya que la clave de la tabla usuario es autonumérica y el nombre del usuario es un campo diferente.
Lo tengo de esta manera para que el nombre del usuario se pueda modificar sin tener que cambiar las relaciones con el resto de los registros relacionados en la base de datos (mediante Foreign keys con la tabla de usuarios).
Para solucionarlo, me dispongo a implementar mi propio módulo de autentificación y autorización.
Hay que tener en cuenta que este módulo está implentado para el uso con la estructura de la base de datos que yo utilizo, la misma en todas mis aplicaciones.

Entorno.

Tomcat 5.0.28
Sun JDK 1.4.2.08

Objetivos.

El objetivo de este documento no es aprender a implementar un Realm desde 0, sino desarrollar uno propio partiendo del org.apache.catalina.realm.RealmBase.

Solución.

La clase abstracta RealmBase nos facilita la vida a la hora de implementar nuestros propios Realm.
El que nosotros vamos implementar es muy parecido al DataSourceRealm, solo que en vez de pasar como parámetros los campos y tablas para que él construya la consulta, le vamos a pasar la consulta a nuestra medida.
Esta es la descripción de nuestro Realm:
/**
 * Autentifica un usuario mediante un pool de conexiones y dos queries.
 * Se debe indicar en la inicialización:
* dataSourceName: Pool de conexiones. Ejemplo: jdbc/mypool * queryUser: * Query para obtener el password y el id del usuario logado. * Como primer y único parámetro de la query (la ?) será el nombre del usuario. * En la "select list", el primer campo será el ID del usuario y el segundo el campo con el password. * ejemplo: SELECT UserId, Password FROM USUARIO WHERE UserName=?; * queryRoles: * Query para obtener la lista de roles del usuario. * Como primer y único parámetro de la query (la ?) será el id del usuario, es decir, el primer campo de la select list de queryUser. * En la "select list", el único primer campo será el campo con el role. * ejemplo: SELECT RoleName FROM ROLES WHERE userId=?; * @author angel * */

Implementación.

Lo primero que hacemos es bajarnos los fuentes del DataSourceRealm para tomarlos como referencia.
Partiendo de estos, nos fijamos que existe un método de inicialización, el cual construye las dos queries. Este método es parte de la implementación del interface Lifecycle.
Este método, en nuestro caso, sobra, ya que la query la pasamos como parámetros y no necesitamos crear las queries.
Otra diferencia en el código es el método protected Principal authenticate(Connection dbConnection, String username, String credentials); ya que las queries que nosotros usamos cumplen con otras condiciones (en la consulta de los roles, la clave no es el código metido por el usuario, sino el código del usuario en la base de datos).
A parte de esto, todo queda prácticamente igual.

Junto a la implementación del interface hay que generar un fichero xml, que será el que lea el Listener del tomcat para instalar y poder usar el Realm que hemos implementado.
La verdad que he encontrado muy poca documentación al respecto (y ninguna en español, aunque a estas alturas eso ya no debería ser problema).
Instalación.
Aquí es donde me he pasado más tiempo y me explico más adelante.
Una vez empaquetado todo (implementación y xml), se debe copiar el jar en $TOMCAT_HOME/server/lib
En el $TOMCAT_HOME/conf/server.xml se debe indicar un listener para inicializar nuestro Realm.
El código, en mi caso, es el siguiente:
     <Listener
         className   = "org.apache.catalina.mbeans.ServerLifecycleListener"
         debug       = "0"
         descriptors = "/com/acervera/commons/realm/mbeans-descriptors.xml"
     />
Una vez hecho esto, ya podemos usar nuestro Realm como comoes habitual.
Para ver ejemplos, http://jakarta.apache.org/tomcat/tomcat-5.0-doc/realm-howto.html
En mi caso, instalo los realms en el contexto. Cada aplicación tiene el suyo propio.
Para nuestra implementación quedaría de la siguiente manera:
	<Realm
		className="com.acervera.commons.realm.CustomQueryDataSourceRealm"
		localDataSource="true"
		dataSourceName="jdbc/INTRANETDB"
		queryUser="SELECT ID, PASSWORD FROM USUARIO WHERE CODIGO=?"
		queryRoles="SELECT ROLE FROM USUARIO_ROLE WHERE ID=?"
	/>
Configurar la aplicación para que use el Realm está ampliamente explicado en multitud de artículos en internet.
Una vez modificado el web.xml a nuestras necesidades, nos disponemos a arrancar el servidor y es aquí donde vienen los problemas.

Problemas

Al levantar el servidor me encuentro con el siguiente error:
GRAVE: Begin event threw error
java.lang.NoClassDefFoundError: org/apache/catalina/realm/RealmBase
        at java.lang.ClassLoader.defineClass0(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:539)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:123)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:251)
        at java.net.URLClassLoader.access$100(URLClassLoader.java:55)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:194)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:187)
        at org.apache.catalina.loader.StandardClassLoader.findClass(StandardClassLoader.java:485)
        at org.apache.catalina.loader.StandardClassLoader.loadClass(StandardClassLoader.java:820)
        at org.apache.catalina.loader.StandardClassLoader.loadClass(StandardClassLoader.java:721)
        at org.apache.catalina.loader.StandardClassLoader.loadClass(StandardClassLoader.java:803)
        at org.apache.catalina.loader.StandardClassLoader.loadClass(StandardClassLoader.java:721)
        at org.apache.commons.digester.ObjectCreateRule.begin(ObjectCreateRule.java:252)
        at org.apache.commons.digester.Rule.begin(Rule.java:200)
        at org.apache.commons.digester.Digester.startElement/images/emoticons/laugh.gifigester.java:1273)
        at org.apache.catalina.util.CatalinaDigester.startElement(CatalinaDigester.java:65)
        at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source)
        at org.apache.xerces.parsers.AbstractXMLDocumentParser.emptyElement(Unknown Source)
        at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanStartElement(Unknown Source)
        at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
        at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
        at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
        at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
        at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
        at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
        at org.apache.commons.digester.Digester.parse/images/emoticons/laugh.gifigester.java:1567)
        at org.apache.catalina.core.StandardHostDeployer.install(StandardHostDeployer.java:488)
        at org.apache.catalina.core.StandardHost.install(StandardHost.java:863)
        at org.apache.catalina.startup.HostConfig.deployDescriptors(HostConfig.java:483)
        at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:427)
        at org.apache.catalina.startup.HostConfig.start(HostConfig.java:983)
        at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:349)
        at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
        at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1091)
        at org.apache.catalina.core.StandardHost.start(StandardHost.java:789)
        at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1083)
        at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:478)
        at org.apache.catalina.core.StandardService.start(StandardService.java:480)
        at org.apache.catalina.core.StandardServer.start(StandardServer.java:2313)
        at org.apache.catalina.startup.Catalina.start(Catalina.java:556)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke/images/emoticons/laugh.gifelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:324)
        at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:287)
        at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:425)
04-jul-2005 3:58:31 org.apache.catalina.startup.HostConfig deployDescriptors
Después de buscar por internet y buscar y volver a buscar. Después de tirarme toda la noche dandole vueltas, encuentro la solución.
La posición del Listener en el server.xml es incorrecta.
Tenemos que poner nuestro Listener después de
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>

Fuentes

Implementación de ejemplo [CustomsRealm.tar.gz]

Enlaces.

http://jakarta.apache.org/tomcat/tomcat-5.0-doc/index.html
http://jakarta.apache.org/tomcat/tomcat-5.0-doc/realm-howto.html
http://jakarta.apache.org/tomcat/tomcat-5.0-doc/mbeans-descriptor-howto.html

Copyright (C) 2005 Angel Cervera Claudio
Se puede distribuir libremente, siempre y cuando se haga referencia al documento original.

Posted by angel at 2:12 PM in Java

jueves, 7 julio 2005

Direcciones de interés [Java]

A continuación listo urls interesante relacionadas con java y j2ee:
Posted by angel at 9:13 AM in Java