Archive

Author Archive

Conexiones seguras SSL y certificado cliente

04/25/2012 Leave a comment

Conexiones seguras SSL con certificado cliente

Primero vamos a ver los pasos necesarios para crear, firmar y configurar un certificado de servidor que se utilizará para cifrar la conexión. Y luego vamos a crear y configurar otro certificado que se utilizará en la parte cliente como certificado cliente para identificar el cliente que hace la petición.

En esta guía vamos a utilizar un Tomcat 7.0.23, java 7u3 y Apache Httpclient 4.1.1.

Antes de empezar vamos a matizar algunos conceptos que vamos a utilizar. Para realizar las conexiones SSL y autenticarnos con los certificados de cliente utilizaremos diferentes entradas del keystore. Cada una de estas entradas es un par clave privada clave pública, donde la clave pública se encuentra envuelta en un certificado X.509 v3 que por defecto está autofirmado (esto luego lo cambiaremos), esta cadena de certificados es guardada como un único elemento. El exportar una entrada lo que estamos exportando es el certificado que envuelve la clave pública. En la importación de certificados hay dos casos que se explican más abajo.

Nota: En algunos códigos de ejemplo se han tenido que meter saltos de línea para que el texto entrase. Es posible que estos saltos de línea tengan que ser eliminados para el correcto funcionamiento de los comandos.

Conexión SSL

Generar las claves, certificado SSL

Primero tenemos que crearnos un par de claves en nuestro keystore que se utilizarán como certificado SSL en el servidor

keytool -genkeypair -keystore server.keystore -alias certSSL -dname CN=localhost
  • -keystore: Es la ruta al archivo keystore que contiene la nueva entrada que se va a generar. Este será el archivo que leerá nuestro servidor para cifrar la conexión.
  • -alias: Es el alias con el que vamos a identificar a está entrada dentro del keystore.
  • -dname: Es el nombre del host del servidor que va a cifrar la conexión en formato CN=host_name. Cuando el cliente haga una petición a nuestro servidor resolverá en su /etc/hosts el host o ip que pongamos en la URL y utilizará ese nombre para validar el certificado del servidor. Si no coincide, no aceptará la petición.

Primero nos pedirá una contraseña para el keystore si el keystore no existe y luego nos pedirá confirmarla. Luego nos pedirá una contraseña para la clave que va a generar y que la volvamos a escribir, si no ponemos ninguna utilizará la del keystore.

El certificado que hemos generado arriba está autofirmado. Eso quiere decir que no ha sido firmada por otra clave (privada). Es muy útil que tengamos nuestro certificado firmado por otro que funcione como autoridad certificadora (CA), de esta forma si el cliente tiene esa CA en su baúl (truststore), todo certificado firmado por esa CA será de confianza y no tendremos que ir añadiendolos independientemente. Luego hablaremos de cómo añadir CA al baúl cliente.

Firmar certificado

Para firmar un certificado primero tenemos que hacer una petición de firmado de certificado (CSR) del certificado que queremos firmar.

keytool -certreq -keystore server.keystore -alias certSSL -file certSSL.csr
  • -keystore: Es la ruta al archivo keystore que contiene el certificado que queremos firmar.
  • -alias: Alias que identifica la entrada que contiene el certificado que vamos a firmar.
  • -file: Ruta al archivo que va a guardar la petición de firmado.

En este proceso te pedirá la contraseña del keystore y si la contraseña de la clave es distinta también te la pedirá. Ahora tenemos dos opciones le pedimos a una autoridad certificadora externa que nos firme nuestro CSR (VeriSign, Thawte,…) o lo firmamos nosotros con una clave privada nuestra.

Firma CA externa

Si elegimos a la autoridad externa, tendremos que enviarle el CSR a parte de otros datos que nos pida. La CA nos devolverá un nuevo certificado, que es el nuestro firmado por ella.

Firma con nuestro CA

Si no tenemos una clave privada para firmar, tendremos que generarla. Se hace igual que la que hemos generado antes

keytool -genkeypair -keystore ca.keystore -alias myca -dname CN=CA
  • -keystore: Es la ruta al archivo keystore que contiene la clave que se va a generar. Es recomendable que sea distinto al que hemos usado para SSL. Luego exportaremos el este certificado y se lo añadiremos al keystore de SSL con un alias nuevo (por la forma de añadirlo se guardará como una entrada de certificado de confianza).
  • -alias: Es el alias con el que vamos a identificar a está entrada dentro del keystore.
  • -dname: Puede ser lo que quieras.

Este comando te pedirá la contraseña del keystore y luego la contraseña de la clave que acaba de generar. Ahora firmamos el CSR con nuestra clave privada bajo el alias myca.

keytool -gencert -keystore ca.keystore -alias myca -ext san=dns:ca1
 -infile certSSL.csr -outfile signedCert.cert
  • -keystore: Es la ruta al archivo keystore que contiene la clave que antes hemos generado para firmar la CSR.
  • -alias: Alias de la clave que vamos a usar para firmar la CSR.
  • -ext: Extensiones X.509 que será embebidas en el certificado que vamos a firmar (fuera del ámbito del documento).
  • -infile: Ruta al archivo que tiene la solicitud de firma CSR.
  • -outfile: Ruta al archivo en el que se guardará el certificado (certSSL) firmado por nuestro CA.

En el proceso te pedirá la contraseña del keystore y si es distinta la contraseña de la clave myca.

Añadir certificado firmado

Da lo mismo el método de firmado elegido, al final tenemos un nuevo archivo (el que nos devuelva la CA externa o el que hemos generado nosotros signedCert.cert) que contiene la cadena de cerificados. Ahora hay que añadir ese certificado a nuestro keystore.

keytool -importcert -keystore server.keystore -file signedCert.cert -alias certSSL
  • -keystore: Es la ruta al archivo keystore donde queremos guardar la nueva clave firmada.
  • -file: Ruta al archivo que tiene la clave firmada.
  • -alias: Alias de la clave sin firmar que va a ser sobrescrito con la nueva clave firmada.

En el proceso te pedirá la contraseña del keystore y, si es distinta, la contraseña de la entrada con alias certSSL.

Si faltase algún certificado de los que componen la cadena de certificados que estamos añadiendo daría un error y no lo añadiría. Habría que añadir los certificados que faltasen (ver Añadir certificado CA).

Configurar servidor

Ya tenemos nuestro keystore con la cadena de certificados y clave privada que vamos a utilizar para la conexión SSL. Ahora hay que configurar el servidor para que utilice ese certificado y clave privada. En el server.xml definimos un nuevo conector de la siguiente manera

<Connector protocol="org.apache.coyote.http11.Http11Protocol" port="18081" 
minSpareThreads="5" enableLookups="true" disableUploadTimeout="true" 
acceptCount="100" maxThreads="200" scheme="https" secure="true" 
SSLEnabled="true" keystoreFile="server.keystore" keystorePass="cambiala" 
keyAlias="certSSL" keyPass="cambialaTambien" sslProtocol="TLS" />
  • port: Puerto donde va a escuchar nuestras peticiones.
  • keystoreFile: Es la ruta al archivo keystore donde tenemos guardada la cadena de certificados y clave privada que vamos a usar para la conexión SSL.
  • keystorePass: Contraseña del keystore.
  • keyAlias: El alias de la entrada del keystore que vamos a utilizar para cifrar la conexión.
  • keyPass: Contraseña de la entrada identificada con el alias especificado en keyAlias.

Configurar cliente

Si hemos firmado el certificado que el servidor utiliza para la conexión SSL con una CA externa, entonces no tenemos que hacer nada especial ya que el certificado de esa CA externa seguramente ya esté en baúl de confianza. Pero si hemos utilizado nuestro propio certificado, tenemos que añadir ese certificado al baúl de confianza que va a utilizar nuestro cliente. Hay distintas formas de hacer esto, voy a explicar la más localizada, sólo afectará a nuestro cliente. Primero exportamos el nuestro certificado de CA como se ha hecho arriba, pero en vez de importarlo en el keystore del sevidor lo añadimos al truststore del cliente

keytool -importcert -keystore client.truststore -file ca.cer -alias certSSL
  • -keystore: Ruta al archivo keystore donde vamos a guardar certificado que firma la clave utilizada para la conexión SSL.
  • -file: Ruta del archivo donde se esta el certificado.
  • -alias: Alias con el que se va a guardar la entrada del certificado de CA.

Ahora tenemos que decir a nuestro código que utilice este keystore como truststore. Primero obtenemos el truststore

FileInputStream instream = new FileInputStream(new File(TRUSTSTORE_PATH)
KeyStore truststore  = KeyStore.getInstance(KeyStore.getDefaultType());
truststore.load(instream, TRUST_STORE_PASS.toCharArray());

Luego creamos una factoría de sockets que utilice nuestro truststore y un esquema (scheme) para https que utilice esta factoría de sockets. Y registramos este esquema en el gestor de conexiones (connectionManager) de nuestro cliente.

SSLSocketFactory socketFactory = new SSLSocketFactory(truststore);
Scheme sch = new Scheme("https", 18081, socketFactory);
client.getConnectionManager().getSchemeRegistry().register(sch);

El código resultante sería algo así:

public class Client {

	private final static String URL = "https://localhost:18081/appSSL";
	private final static String TRUESTORE_PATH = "client.truststore";
	private static final String KEY_STORE_PASS = "cambialaTrust";

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		DefaultHttpClient client = new DefaultHttpClient();

		try (FileInputStream instream = new FileInputStream(new File(
                            TRUESTORE_PATH));){
			KeyStore truststore  = KeyStore.getInstance(
                            KeyStore.getDefaultType());

		        truststore.load(instream, KEY_STORE_PASS.toCharArray());

	        	SSLSocketFactory socketFactory = 
                            new SSLSocketFactory(truststore);
	        	Scheme sch = new Scheme("https", 18081, socketFactory);
		        client.getConnectionManager().getSchemeRegistry()
                            .register(sch);

			HttpGet httpget = new HttpGet(URL);
			HttpResponse response;

			response = client.execute(httpget);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
			    BufferedReader reader = new BufferedReader(
                                new InputStreamReader(entity.getContent()));

			    String text;
			    while ((text = reader.readLine()) != null)
			    	System.out.println(text);
			}
		} catch (IOException | CertificateException | KeyStoreException 
                             | NoSuchAlgorithmException | KeyManagementException 
                             | UnrecoverableKeyException e) {
			e.printStackTrace();
		}

	}

}

Certificado cliente

Una de las formas que tenemos de identificar al cliente que está haciendo la petición es mediante un certificado de cliente. El cliente utiliza el par certificado-clave privada para identificarse contra el servidor.

Generar par certificado-clave privada

La entrada se genera igual que para el caso de la conexión SSL, pero en este caso el valor que pongamos en el parámetro -dname va a ser lo que luego nos identificará en el servidor.

keytool -genkeypair -keystore client.keystore -alias clientCert -dname CN=Nikola
  • -keystore: Es la ruta al archivo keystore que va contener el par certificado-clave que se va a generar.
  • -alias: Es el alias con el que vamos a identificar a está entrada dentro del keystore.
  • -dname: Es el nombre que luego nos identificará en el servidor.

Primero nos pedirá una contraseña para el keystore si el keystore no existe y luego nos pedirá confirmarla. Luego nos pedirá una contraseña para la entrada que va a generar y que la volvamos a escribir, si no ponemos ninguna utilizará la del keystore.

Configuración servidor

Esto se puede hacer de dos formas según quieras que sea el servidor o la aplicación quien autentique al cliente.

Autenticación por aplicación

En el server.xml tenemos que modificar nuestro conector SSL añadiéndole los siguientes atributos:

  • truststoreFile=“client.keystore”
  • truststorePass=“cambiala”
  • clientAuth=“false”

quedaría así:

<Connector protocol="org.apache.coyote.http11.Http11Protocol" port="18081" 
minSpareThreads="5" enableLookups="true" disableUploadTimeout="true" 
acceptCount="100" maxThreads="200" scheme="https" secure="true" 
SSLEnabled="true" keystoreFile="/var/lib/tomcat7/conf/pruebando" 
keystorePass="asdasd" keyAlias="ssl" keyPass="asdasd" 
truststoreFile="client.keystore" truststorePass="cambiala" clientAuth="false" 
sslProtocol="TLS" />
  • truststoreFile: Ruta al archivo keystore con los certificados de los clientes que vamos a autenticar.
  • truststorePass: Contraseña del keystore.

En el web.xml de la aplicación tendríamos que añadir las restricciones de seguridad a los recursos de la aplicación e indicar el tipo de autenticación que queremos realizar. Podría ser algo así:

<login-config>
    <auth-method>CLIENT-CERT</auth-method>
    <realm-name>Mi realm</realm-name>
</login-config>

<security-role>
    <description>Cliente con certificado</description>
    <role-name>pruebaClientCert</role-name>
</security-role>

<security-constraint>
    <display-name>Toda la aplicacion</display-name>
    <web-resource-collection>
        <web-resource-name>Todo</web-resource-name>
        <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>pruebaClientCert</role-name>
    </auth-constraint>
</security-constraint>

Estás líneas en el web.xml indican que el método de autenticación va a ser por certificado de cliente (<auth-method>CLIENT-CERT</auth-method>) que el rol necesario para poder acceder a cualquier recurso de la aplicación es “pruebaClientCert”.

Y luego en donde estén definidos los usuarios las contraseñas y los roles tenemos que meter la siguiente entrada:

  • Nombre de usuario: Es el nombre que definimos el crear la clave del cliente en el parámetro -dname. (En nuestro ejemplo “CN=Nikola”).
  • Contraseña: null
  • Roles: Los roles a los que van a pertenecer a este cliente. (En nuestro caso, como mínimo, pruebaClientCert).

Para el caso del realm UserDatabaseRealm habría que añadir algo así:

<role rolename="pruebaClientCert"/>
...
<user username="CN=Nikola" password="null" roles="pruebaClientCert" />

Autenticación por servidor

Configuración cliente

Vamos a utilizar la entrada que hemos generado antes para identificar al cliente que hace la petición, para esto vamos a tener que decir a nuestro código que utilice este keystore. Primero obtenemos el keystore

FileInputStream instreamKey = new FileInputStream(new File(KEYSTORE_PATH)
KeyStore keystore  = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(instreamKey, KEYSTORE_PASS.toCharArray());

Luego modificamos la factoría de sockets que hemos creado antes para que utilice nuestro keystore.

SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore, KEYSTORE_PASS, 
trustStore);

El código resultante sería algo así:

public class Atacando {

	private final static String URL = "https://localhost:18081/appSSL";
	private final static String TRUSTSTORE_PATH = "client.truststore";
	private static final String TRUSTSTORE_PASS = "cambialaTrust";

	private final static String KEYSTORE_PATH = "client.keystore";
	private static String KEYSTORE_PASS = "cambiala";

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		DefaultHttpClient client = new DefaultHttpClient();

		try (FileInputStream instream = new FileInputStream(new File(
                              TRUSTSTORE_PATH));
			   FileInputStream instreamKey = 
                              new FileInputStream(new File(KEYSTORE_PATH));){
			KeyStore trustStore  = KeyStore.getInstance(
                              KeyStore.getDefaultType());
			KeyStore keyStore  = KeyStore.getInstance(
                              KeyStore.getDefaultType());

	                trustStore.load(instream, TRUSTSTORE_PASS.toCharArray());
	                keyStore.load(instreamKey, KEY_STORE_PASS.toCharArray());

	                SSLSocketFactory socketFactory = new SSLSocketFactory(
                               keyStore, KEYSTORE_PASS, trustStore);
         	        Scheme sch = new Scheme("https", 18081, socketFactory);
        	        client.getConnectionManager().getSchemeRegistry()
                               .register(sch);

			HttpGet httpget = new HttpGet(URL);
			HttpResponse response;

			response = client.execute(httpget);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
			    BufferedReader reader = new BufferedReader(
                                 new InputStreamReader(entity.getContent()));

			    String text;
			    while ((text = reader.readLine()) != null)
			    	System.out.println(text);
			}
		} catch (IOException | CertificateException | KeyStoreException 
                          | NoSuchAlgorithmException | KeyManagementException 
                          | UnrecoverableKeyException e) {
			e.printStackTrace();
		}
	}
}

AutoBean, JSON con GWT

04/03/2012 1 comment

En GWT a la hora de interactuar desde la parte cliente con el servidor utilizamos los servicios y estamos acostumbrados a enviar objetos y recibir objetos. Cuando trabajamos con formularios podemos seguir aprovechándonos de esta característica enviando desde el servidor objetos convertidos a JSON y reconstruyéndolos en el cliente con AutoBean.

Antes de meternos en faena, formularios en GWT

Para entender mejor el uso que vamos a explicar de los AutoBean’s, vamos a describir brevemente como funcionan los formularios en GWT

El constructor sin parámetros de FormPanel, crea un iframe para este formulario de forma que cuando hagas submit se hará sobre este iframe evitando que se recargue toda la página. Cuando el servidor responda a esta petición, el formulario lanzará el evento onSubmitComplete y se podra recuperar el texto devuelto con el método getResults() del evento SubmitCompleteEvent. Este es el constructor que nosotros vamos a usar en esta entrada.

También hay otros constructores que te permiten relacionar tu formulario con un iframe, pero en estos casos el evento onSubmitComplete no es lanzado y hay que utilizar otros métodos para recuperar la respuesta del servidor.

Manos a la obra

Primero vamos a hacer un breve descripción de los pasos que va a dar nuestra aplicación:

  1. Se hace submit de un formulario
  2. El servidor procesa la petición y se genera un objeto de respuesta
  3. Con AutoBean serializamos el objeto en JSON y lo enviamos al cliente
  4. El cliente recupera el texto JSON y reconstruye el objeto inicial con AutoBean

Requisitos

El AutoBean que vamos a definir se utiliza tanto en la parte de cliente como en la parte de servidor, tiene que estar en una paquete compartido de GWT.

Los objetos que vamos a serializar (y deserializar) tienen que ser implementaciones de una interfaz y esa interfaz tiene que definir un bean, es decir, sus métodos tienen que ser getters (getX e isX). AutoBean trabaja con interfaces de objetos.

En el gwt.xml tenemos que importar el módulo de AutoBean:

<inherits name="com.google.web.bindery.autobean.AutoBean" />

Y tenemos que añadir la librería gwt-servlet-deps.jar al classpath de la aplicación.

AutoBeanFactory

Para crear AutoBean’s tenemos que definir una interfaz que extienda de la interfaz AutoBeanFactory y para cada objeto que vamos a serializar tenemos que tener un método en esa interfaz que devuelva un AutoBean parametrizado con la interfaz de dicho objeto que vemos a serializar.

public interface MyAutoBeanFactory extends AutoBeanFactory {
public AutoBean<IMyBean> makeMyBean();
}

MyAutoBeanFactory es la interfaz que vamos a utilizar para obtener los AutoBean’s

IMyBean es la interfaz que debe implementar el bean que vamos a querer serializar.

Parte Servidor

Para obtener el objeto factoría que vamos a utilizar para obtener los AutoBean’s, llamamos al método create de la clase AutoBeanFactorySource pasándole la clase de la interfaz de nuestra factoría. Ahora podemos crear el AutoBean para el objeto que vamos a serializar, donde myBeanObject es el objeto que vamos a serializar. Es importante poner como contentType text/html para que el navegador lo pinte tal y como viene (no intente formatearlo de alguna manera).


MyAutoBeanFactory beanFactory = AutoBeanFactorySource.create(MyAutoBeanFactory.class);
AutoBean<IMyBean> bean = beanFactory.create(IMyBean.class, myBeanObject);
String json = AutoBeanCodex.encode(bean).getPayload();
BufferedWriter bf=new BufferedWriter(response.getWriter());
response.setContentType("text/html");
bf.write(json);
bf.flush();
bf.close();

este código serializaría el objeto myBeanObject y lo enviaría como respuesta al cliente. (El objeto response es de la clase HttpServletResponse).

Parte Cliente

Ahora vamos a ver el código de como recuperar el texto que ha enviado el servidor como respuesta del submit del formulario y convertir el texto JSON en nuestro objeto a través de AutoBean.


formPanel.addSubmitCompleteHandler(new SubmitCompleteHandler() {
@Override
public void onSubmitComplete(SubmitCompleteEvent event) {
MyAutoBeanFactory beanFactory = GWT.create(MyAutoBeanFactory.class);
String json = event.getResults();
AutoBean<IMyBean> autoBeanClone = AutoBeanCodex.decode(beanFactory, IMyBean.class, json);
IMyBean bean = autoBeanClone.as();
...
}
});

En el código de ejemplo, cuando se lanza el evento SubmitCompleteEvent del formulario, creamos el objeto MyAutoBeanFactory y el texto JSON del servidor, utilizamos el método AutoBeanCodex.decode(…) que nos recupera el AutoBean para nuestra interfaz.

Un posible uso de todo esto es a la hora de tener que subir un archivo al servidor. En este caso estamos casi obligados a usar un formulario y esta podría ser una buena forma de procesar la respuesta del servidor.

El negocio de MySql cambia

09/28/2011 3 comments

Nuestra base de datos favorita cambia la forma de hacer dinero. Oracle va a mantener el núcleo de MySql como hasta ahora y luego va a montar un ecosistema de extensiones que no van a ser libres ni de gratis. Me pregunto ¿qué dejaran en el core y que quedará fuera? ¿El driver de balanceo de carga dónde estará?

La noticia bien contada: http://javahispano.org/portada/2011/9/28/oracle-cambia-el-modelo-de-negocio-en-torno-a-mysql-ahora-es.html

Casi decidida la sintaxis de las closures para Java 8

09/15/2011 1 comment

Después de mucho discutir sobre si el lenguaje java debería o no tener closures, al final se decidió que si. Luego tocaba la, no menos complicada, labor de decidir la sintaxis. Algunas de las propuestas fueron:

#{Foo foo -> foo.bar()}

int(int a, int b) { return a – b; }

….

Pero al final parece que ha ganado la sintaxis utilizada en C# y scala:

lambda = ArgList Arrow Body
   ArgList = Identifier
             | "(" Identifier [ "," Identifier ]* ")"
             | "(" Type Identifier [ "," Type Identifier ]* ")"
   Body = Expression
             | "{" [ Statement ";" ]+ "}"

Algunos ejemplos serían:

  1. x => x + 1
  2. (x) => x + 1
  3. (int x) => x + 1
  4. (int x, int y) => x + y
  5. (x, y) => x + y
  6. (x, y) => { System.out.printf(“%d + %d = %d%n”, x, y, x+y); }
  7. () => { System.out.println(“I am a Runnable”); }

A mi, eso de que puedas definir la closure sin indicar de que clase son las variables, en un lenguaje fuertemente tipado como es Java, no lo veo claro (ejemplos 2, 5 y 6)

Un compañero de JavaHispano nos muestra un ejemplo más completo de como van a funcionar estar closures:

// sin closures
List data = new Vector();
Collections.sort( data, 
                  new Comparator()
                      { public int compare(Object a, Object b)
                               { return ((String) a).length()- ((String) b).length();  }
                      }
                );

// con closures
List data = new Vector();
Collections.sort(data, (a, b) => { ((String) a).length()- ((String) b).length(); } );

Para poder empezar a usar las closures vamos a tener que esperar hasta octubre del 2012, si Oracle no hace ninguna pirula, ya que es para cuando tienen pensado sacar Java 8.

Dejo un par de enlaces sobre la sintaxis de la closures en JavaHispano y la fuente original correos de openJDK.

Categories: Tecnologías Tags: , , , ,

Aplicaciones escalables con GWT (Patrón MVP)

07/18/2011 2 comments

Una de las mejores soluciones de diseño a la hora de hacer una aplicación con GWT de cierto tamaño, en la que van a trabajar varias personas simultáneamente y minimizando el acoplamiento es MVP (Modelo Vista Presentador).

  • Modelo: representa los objetos de negocio.
  • Vista: cada vista contendrá los componentes necesarios para formar la interfaz de usuario y es responsable de su disposición. No sabe nada sobre el modelo, por ejemplo, sólo sabe que muestra dos etiquetas y un campo de textopero no sabe que eso proviene de un objeto de negocio.
  • Presentador: es el que tiene toda la lógica de la aplicación. Como norma general, cada vista tendrá un presentador que se encargará de darle el contenido que mostrará y manejar los eventos que se producen en ella.

Otro componente fundamental en el patrón es el AppController que se encarga de la lógica de transición entre vistas y de la gestión del historial de navegación.

Para ver este patrón con más detalle y un ejemplo de implementación, ver la documentación de google y si te encuentras con fuerzas aquí tienes la segunda parte.

Tu código tiene bugs? Findbugs

07/18/2011 1 comment

Logo FindbugsSi cuatro ojos ven más que dos, Findbugs ve más que cuatro. Está es la conclusión a la que llegas cuando ves los errores que te encuentra este analizados de código.

Existen diferentes analizadores estáticos de código que nos pueden ayudar a encontrar posibles errores o a optimizar el funcionamiento de nuestra aplicación. Uno de ellos es Findbugs que analiza el bytecode (no los fuentes) y nos saca los colores. Puede funcionar como programa independiente o como plugin del Eclipse y también se puede integran con Jenkins. Su uso y configuración es muy sencillo e intuitivo.

Descargar Findbugs y sencilla guía de instalación y uso.

Categories: 3rd Party Software Tags: , , ,

Supercurso inaccesible

07/18/2011 Leave a comment

Así es el curso que nos ofrece JavaSpecialists.EU, avalado por Dr. H Kabutz (un pepino). Supercurso: profundizando en los conceptos fundamentales del lenguaje y la plataforma java (hilos, memoria, reflexión,…), e inaccesible: a un precio prohibitivo 2.500€ por cuatro días.

Os dejo el enlace por si queréis salivar un poco. Java Specialist Master

%d bloggers like this: