Etiqueta: estándares

Calentito: WCAG 2.0 ya es una recomendación del W3C

11 dic 2008

Logotipo del World Wide Web Consortium

He leído en la lista de Accesoweb de Sidar, que el El W3C acaba de publicar una nueva lista de recomendaciones en materia de accesibilidad. Es la WCAG 2.0 (Web Content Accesssibility Guidelines 2.0).

El W3C es la organización de mayor reconocimiento en materia de estándares web. Las especificaciones en esta materia de las administraciones públicas españolas, como la Junta de Andalucía o el Gobierno de España, hacen referencia siempre a las WCAG por lo que las pautas se convierten para nosotros en normas de facto.

Era evidente la necesidad de una revisión profunda de algunas de las pautas. Las indicaciones sobre uso de h1-h6 para identificar encabezados por ejemplo, con un uso más semántico que “topográfico”, es indicativo de esta nueva orientación.

Las nuevas recomendaciones se articulan sobre cuatro patas que debe tener cualquier contenido web:

  • Perceptible (por ejemplo a través de alternativas textuales para imágenes, subtítulos para audio, presentación adaptada y contraste de colores);
  • Operable (tratando el acceso del teclado, el contraste de colores, la coordinación de la entrada de datos, evitando el control automático y control de la navegación);
  • Comprensible (teneniendo en cuenta la legibilidad y predicción del contenido, y la asistencia de introducción de datos); y
  • Robusto (por ejemplo, manejando la compatibilidad con las tecnologías asistivas).

De todas maneras, mientras que la normativa con respecto a accesibilidad web no contemple un órgano regulador o una certificación oficial homologada, se seguirán poniendo alegremente en los portales las famosas “A”, “AA”, e incluso “AAA” (que se siguen manteniendo sin introducir la pintoresca A+) como quien tunea su buga con la pegatina de SuperTurbo, sin pasar siquiera los test automáticos, e incautos clientes que se verán deslumbrados con el dorado sello. De risa. O de pena :S

La nota de prensa:
http://www.w3.org/2008/12/wcag20-pressrelease.html

Y la recomendación en
http://www.w3.org/TR/WCAG20/

Leyendo un feed OpenSearch con código Java

25 nov 2008

De forma muy resumida, OpenSearch es una colección de formatos abiertos y estándares desarrollados por A9 (Amazon), que persiguen resolver 2 escenarios principalmente:

  • Caso 1: Permitir a una aplicación publicar de una forma estándar resultados de búsqueda; estos resultados pueden ser consumidos posteriormente por una aplicación cliente. Se basa en un metamodelo estandarizado publicado bajo una fuente de sindicación estándar como RSS o Atom. Podemos ver un ejemplo de resultado de búsqueda en formato OpenSearch en esta URL de indeed.com.
  • Caso 2: Describir (autodescribir) servicios de búsqueda. Es lo que utiliza por ejemplo Firefox 3 para ofrecernos búsquedas inteligentes.

En este post vamos a describir cómo leer resultados de búsqueda en formato OpenSearch (caso 1). Para el caso 2, recomendamos la lectura de un post de 11870.com que describe a la perfección cómo describir nuestro buscador.

Si nos fijamos en el código fuente de respuesta de la URL comentada de indeed, veremos que en este caso se está devolviendo sobre RSS una información general sobre la búsqueda más un conjunto de resultados de búsqueda (items), los cuales pueden ser incluso geolocalizados.

En Java, este RSS (o Atom) podría ser leído con cualquier intérprete de XML, o mejor con alguna librería específica de este tipo de feeds, como Rome o Apache Abdera, o mejor aún, con librerías específicas para OpenSearch. En nuestro caso, debíamos leer la respuesta del API de 11870.com, dentro de un proyecto en el cual deseábamos proponer establecimientos propuestos por los usuarios que estén cercanos a nuestra localización.

A este respecto, cuando he hecho la búsqueda de librerías Java, personal he tenido una sensación agridulce. Si bien los desarrolladores Java solemos ser unos verdaderos privilegiados en cuanto a lo que se refiere a disposición de API’s, en ciertos casos relacionados con web semántica o API’s de web 2.0 tengo la sensación de que otras arquitecturas de desarrollo como PHP, Python o RoR a veces tienen cierta ventaja. En el caso de Java todo son versiones de incubadora, 0.X, etc.

En el caso de librerías Java, una rápida búsqueda nos llevó a decidirnos entre Rome (Sun) y Apache Abdera, escogiendo este último por disponer de mejores ejemplos de los que partir. Además dentro de los committers de Abdera está el supercrack David Calavera, desarrollador de la omnipresente 11870.com.

A continuación incluiremos unos pequeños recortes de código que muestran como leer la respuesta OpenSearch mediante Abdera. En primer lugar, necesitaremos disponer de las librerías. Para ello (en el caso de Maven) incluiremos estas dependencias en nuestro pom.xml:

<dependency>
<groupId>org.apache.abdera</groupId>
<artifactId>abdera-client</artifactId>
<version>0.4.0-incubating</version>
</dependency>

<dependency>
<groupId>org.apache.abdera</groupId>
<artifactId>abdera-extensions-opensearch</artifactId>
<version>0.4.0-incubating</version>
</dependency>

Para poder resolver estas dependencias incluiremos los repositorio Incubating y Snapshot de Apache dentro de <repositories>:

<repository>
<id>apache-incubating</id>
<name>Apache Incubating Repository</name>
<url>http://people.apache.org/repo/m2-incubating-repository/</url>
</repository>
<repository>
<id>apache-snapshots</id>
<name>Apache Snapshot Repository</name>
<url>http://people.apache.org/repo/m2-snapshot-repository/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>

Dado una dirección URL (String urlQuery) donde esté publicada una consulta que responde OpenSearch, podremos invocarla con el siguente código:

Abdera abdera = new Abdera();
Parser parser = abdera.getParser();
URL url = new URL(urlQuery);
Document<Feed> doc = parser.parse(url.openStream(), urlQuery);
Feed feed = doc.getRoot();

Podemos recuperar ciertas propiedades de la respuesta de OpenSearch:

IntegerElement totalResults = feed.getExtension(OpenSearchConstants.TOTAL_RESULTS);
int resultados = totalResults.getValue();

Del mismo modo se pueden recuperar datos como el número de items por página (OpenSearchConstants.ITEMS_PER_PAGE) o el índice inicial de la respuesta, útil cuando hay paginación (OpenSearchConstants.START_INDEX. Es decir, podemos obtener datos OpenSearch del feed mediante feed.getExtension().

A continuación mostramos cómo iterar los items de respuesta del feed:

for (Entry entry : feed.getEntries()) {

    System.out.println(“Title: “+entry.getTitle());
    System.out.println(“Summary: “+entry.getSummary());
    System.out.println(“Id: “+entry.getId().toString());
    System.out.println(“Id: “+entry.getId().toString());

}

También podemos evaluar para cada item (resultado de búsqueda) el valor de extensiones a OpenSearch. Por ejemplo, podemos pretender recuperar los datos de geolocalización en formato GeoRss. Para ello utilizaríamos un código como el que sigue:

QName qnameWhere = new QName(“http://www.georss.org/georss/10″,”where”, “georss”);
Element where = entry.getExtension(qnameWhere);
try {
String geoPos = where.getFirstChild().getFirstChild()
.getText();
String[] posicion = geoPos.split(” “);
if (posicion.length == 2) {

System.out.println(“latitud: “+posicion[0]);
System.out.println(“longitud: “+posicion[1]);
}
} catch (Exception e) {
e.printStackTrace();
}

Es decir, podemos recuperar el valor de un parámetro de una extensión invocando a entry.getExtension, pasando como parámetro un objeto de tipo QName, instanciado como indicamos en el código anterior.

En definitiva, hemos hecho una breve introducción a OpenSearch y mostrado código de ejemplo para interactuar con una respuesta OpenSearch mediante Apache Abdera.

Códigos INE de municipios

29 jul 2008

He venido observando que hay una codificación INE de 6 dígitos en lugar de los 5 dígitos tradicionales. Por ejemplo, donde Sevilla solía tener un código INE 41091, ahora tiene un nuevo código 410917. Este código es el mismo que el anterior, más un dígito adicional que a priori parece ser un dígito de control.

Estos códigos nuevos se pueden descargar en formato Excel de la URL:

http://www.ine.es/daco/daco42/codmun/codmun08/08codmunmapa.htm

Parece ser que la codificación es la anterior, con la adición de un sexto dígito de control, como se menciona en esta dirección (“el último es un dígito de control que, asignado mediante una regla de cálculo, permite la detección de errores de grabación y modificación”).

Sin embargo, no he sido capaz de encontrar ninguna referencia a cómo se realiza este cálculo. En anexos de algunos documentos he encontrado referencias a un cálculo basado en un módulo 11, pero he comprobado que ésta no es la vía correcta.

Posibilidades:

  • El dígito se calcula mediante una fórmula arcana guardada en secreto por alquimistas que perduran desde la época de la piedra filosofal.
  • Es más fácil, pero no está en Google.
  • Está en Google, pero no sé buscar.
  • Es un número aleatorio para jorobar, realmente es una nueva codificación y punto, a guardarla en base de datos. Lo que pusieron mencionando una “regla de cálculo” era para despistar.

Se acepta ayuda. Gracias!

¡Los buenos vamos ganando!

30 oct 2007

Qué alegría me he llevado al revisar las excelentes estadísticas de Google Analytics. Resulta que, estimadísimos lectores, ¡usais más Firefox que IE! ¡Ole vosotros! Al menos en los últimos días de octubre, la distribución queda así:

Distribucion de visitas de navegadores en xnoccio

Es decir, Firefox lidera con un 48,64%, mientras que Explorer le sigue de cerca con un 45,60%, etc. De aquí saco conclusiones:

  1. A poco que pacte Firefox tendrá un gobierno estable. El problema del Explorer es que ha calentado mucho la legislatura de los estándares, y ahora se ha quedado solo.
  2. Los navegadores que intentan respetar los estándares están divididos, pero los que pasan sólo tienen una opción: IE.
  3. ¿¿¿¿¿Quién coño malgasta innova con su PSP para entrar en xnoccio????
  4. Gzip no es un browser, como mucho será un servlet. ¿A quién apuntamos este escaño independiente?

Firefox 3, ansiosos te esperamos :-D

Que es Felix?

19 ago 2007

Esto me pasa por no tener registrado mi nombre… :p

Apache Felix es el nombre del nuevo proyecto Apache que se ha graduado este verano, y que viene a ofrecernos una plataforma completa OSGi que se convierte, junto a Equinox Eclipse, en una de las alternativas mas importantes para la construcción de sistemas modulares en Java.

Aunque reconozco la potencia y éxito de OSGi, para el tipo de aplicaciones Web que solemos desarrollar prefiero Service Provider Interfaces(SPIs) que ofrece un mecanismo mucho mas sencillo para la creación de aplicaciones modulares y que esta disponible de forma estandar en Java SE 6.

En relación a esto, y sin que nos demos cuenta estamos en medio de una gran batalla entre OSGi(JSR 291) y Java Module System (JSR 277), tendremos que estar pendientes para ver cual es la opción que adopta el proximo Java EE 6.

Yusef en la Cartuja

25 may 2007

Ayer estuve en una jornada organizada por Avante Formación en la Cartuja sobre Usabilidad. Un evento de autopromoción, vaya, pero con la presencia de Yusef Hassan, un crack de la usabilidad en España. Lo mejor, casi lo único interesante fue lo que él dijo. Y digo “casi” porque hubo una bollería más que decente en el desayuno, y porque Quino Terceño, de Cero4 nos obsequió con esta perla:

“El programador diseña aplicaciones igual que un minero diseña paisajes: cavando zanjas y haciendo montones”

Citaba a Alan Cooper en su libro About Faces 2.0.

Pardiez, qué lucidez.

Otras cosas que me interesaron:

Yusef: diseño centrado en el usuario; modelo que sustituye al de cascada (secuencial e irreversible) por éste otro, conocido como “modelo lavadora”:

Modelo lavadora del diseño centrado en el usuario
Modelo lavadora del diseño centrado en el usuario

Yusef:

  • El cliente no es el usuario
  • El cliente no es el diseñador
  • Nosotros no somos el usuario
  • Desde que los ratones tienen ruedecita, no es necesario desviar el foco para hacer scroll, por lo que el contenido no tiene por qué comprimirse en una pantalla
  • Quino:

    • Los errores hay que representarlos contextualmente (nos enseñaba el diseño de un procedimiento extenso, con múltiples páginas y formularios)

    Por último, nos metieron con cuña una presentación de Microsoft Expression, para el diseño de interfaces. Para Ethel, la web del futuro es algo así como “Microsoflash 2.0″. Esta chica se ve que no visita mucho el sitio de O’Reilly.
    Supuse que eran ellos quienes pagaban los pastelitos y el café, así que fui prudente y no hice preguntas.

Eligiendo una licencia libre.

14 may 2007

Si la decisión de hacer libre un proyecto o librería ya está tomada, aún queda la ardua labor de elegir la licencia que más nos conviene. En nuestro caso concreto, siendo una PYME, la elección ha sido la GPL. Enumero y explico nuestras motivaciones:

- La licencia GPL es vírica por lo que si algún proyecto utiliza el código liberado, éste tendrá que ser a su vez publicado como GPL. Con esto conseguimos por un lado colaborar con la comunidad y por el otro evitar la competencia desleal de otras empresas del sector, que podrían utilizar el código sin proporcionarnos un beneficio recíproco.

- La licencia GPL nos permite liberar el código y a la vez, como titulares del copyright, seguir utilizando éste, si es necesario, en desarrollos no-libres. Incluso nos permite mantener una licencia dual, comercial y libre (el ejemplo más claro lo tenemos en MySQL).

- Hemos descartado licencias tipo BSD, ya que no nos otorga ningún tipo de protección frente al uso del código por terceras empresas. Incluso Microsoft podría incluir parte de vuestro código (Como el caso típico de la implementación de la pila TCP/IP tomada prestada de BSD) :)

- Otra licencia interesante es la licencia de Apache, pero está más pensada para grupos de proyectos y grandes organizaciones. Estas licencias no son víricas, por lo que son compatibles con cualquier otro proyecto con la única limitación de hay que indicar en los créditos a los autores. Además son licencias muy complejas, más adecuadas para librerías y aplicaciones que se deban integrar con código heterogeneo.

- Usar la GNU GPL exige que todas las versiones mejoradas que se publiquen sean software libre. Con esto evitamos el riesgo de tener que competir con una versión modificada de forma privada de nuestro propio trabajo.

-La LGPL (renombrada a GPL Reducida), es una buena opción, pero nos da menos ventaja por ser autores, ya que al estar pensada inicialmente para librerías, no obliga a que las aplicaciones que hagan uso de éstas, sean a su vez libres.

-La GPL no plantea problemas si utilizamos bibliotecas no GPL, siempre y cuando indiquemos de forma clara su existencia.

-La EUPL, es una apuesta de futuro promovida por la Unión Europea y que tiene previsto adoptar para la liberación de software en las administraciones públicas de Europa. Dado el ámbito público en el que se suelen mover nuestros proyectos, en cuanto esta licencia empiece a funcionar, no cabe duda de que sera nuestra mejor opción.

Quizás la decisión no sea la más adecuada ya que existen licencias libres para todos los gustos:

(Fuente http://opensource.org)

Seamos elegantes

30 abr 2007

Plain Old Semantic HTML (POSH)

Tips: Xml Signature

04 abr 2007

¿Que es?

Es una especificación desarrollada bajo el amparo del w3c (http://www.w3.org/Signature/) que permite la firma( completa o parcial) de documentos utilizando una notación XML estandar. XML Signatures ofrece algunas ventajas frente a la firma tradicional ya que al estar basada en texto plano su estructura es legible por humanos.

Los documentos Xml Signature los podemos clasificar en tres tipos, dependiendo de la asociación con el documento firmado:

  • Enveloped: En el que el documento a firmar y la firma quedan ligados en un único xml. Este es el método mas recomendable para firmar documentos de texto o Xmls.
  • Enveloping: En el que el documento firmado(Debe ser un Xml), adjunta como un nodo mas el elemento Signature.
  • Detached: En el que el documento firmado se mantiene separado de la firma, manteniendo el XMLSignature una referencia al documento.

Un Ejemplito
Ejemplo de fichero XML Signature

Aunque parece un XML con un formato muy complejo, es sencillo de entender, su esquema de definición es :

<element name=“Signature” type=“ds:SignatureType” />
<
complexType name=“SignatureType”>
<
sequence>
<
element ref=“ds:SignedInfo” />
<element ref=“ds:SignatureValue” />
<
element ref=“ds:KeyInfo” minOccurs=“0″ />
<
element ref=“ds:Object” minOccurs=“0″ maxOccurs=“unbounded”/>
</sequence>
<attribute name=“Id” type=“ID” use=“optional” />
</
complexType>

Y buscando en el XML de ejemplo las estructuras definidas en el esquema, podemos ver que SignedInfo contiene la información relacionada con la firma( algoritmo utilizado, etc), en SignatureValue el resultado de la firma( en Base64), en KeyInfo los datos del certificado del firmante, y en Object los datos que se firmaron.

¿Apis para manejar XML Signatures?

En nuestro caso, estamos utilizando la implementación de Apache de XML Security , junto con Bouncy Castle.

XML Singature es un formato que ha llegado para quedarse entre nosotros, espero que esto sirva de una pequeña introducción para que deje de ser un desconocido o simplemente una palabreja, para convertirse en algo palpable y sencillo.

Estandarizando los codigos internos de error

07 feb 2007

Sera deformacion profesional heredada de mi experiencia laboral anterior, pero cuando nos hemos decidido a crear un Java5 enum en nuestras librerias de desarrollo para la estandarizacion de los codigos de error, me he empeñado en reservar/usar los codigos de respuesta del estandard SIP (Session Initiation Protocol). Realmente son un superconjunto de los codigos de respuesta estandard del protocolo HTTP, con los que la mayoria estamos mas que familiarizados, aunque solo sea de navegar en busca del fin de internet (sic).

Basicamente mi idea ha sido reservar todos los codigos de error entre 100 y 699 para codigos compatibles con el estandard SIP:


1xx: Provisional — Respuestas provisionales, de caracter informativo. Se envia un 1xx si se espera que la respuesta final tarde mas de 200ms.
2xx: Success — Para los casos en que todo ha ido bien.
3xx: Redirection — Hacen falta acciones adicionales para completar correctamente la petición.
4xx: Client Error — Errores en capa cliente, o peticiones mal formadas.
5xx: Server Error — Fallos en servidor ante una peticion aparentemente correcta.
6xx: Global Failure — Fallo global.

Obviamente, para un enum que contenga codigos de error, las respuestas informativas o de exito no nos interesan, pero en cualquier caso decidimos reservar esos rangos y no usarlos. Simple cuestion de compatibilidad hacia delante.

Estos codigos no son ningun secreto y estan disponibles en cientos de paginas en internet, pero picarselos en un enum resulta bastante co~azo, la verdad… asi que aqui estan por si alguien quiere reutilizar…


public enum CodigoError{
	//Especial
	/* Copyrighted */
	//0xx - General (Viavansi)
	/* Copyrighted */
	//1xx - Provisional (Standard) - Informativo de progreso - No usar como codigo de error!
	//2xx - Success (Standard) - No usar como codigo de error!
	//3xx - Redirection (Standard)
	SIP_MULTIPLE_CHOICES(300,"Multiple Choices."),//SIP
	SIP_MOVED_PERMANENTLY(301,"Moved Permanently."),//SIP
	SIP_MOVED_TEMPORARILY(302,"Moved Temporarily."),//SIP
	SIP_USE_PROXY(305,"Use Proxy."),//SIP
	SIP_ALTERNATIVE_SERVICE(380,"Alternative Service."),//SIP
	//4xx - Client or Request (Standard)
	SIP_BAD_REQUEST(400,"Bad Request."),//SIP
	SIP_UNAUTHORIZED(401,"Unauthorized. Need to register."),//SIP Proxys should use proxy authorization 407
	SIP_PAYMENT_REQUIRED(402,"Payment Required"),//SIP
	SIP_FORBIDDEN(403,"Forbidden."),//SIP
	SIP_NOT_FOUND(404,"Not Found."),//SIP
	SIP_METHOD_NOT_ALLOWED(405,"Method Not Allowed."),//SIP
	SIP_REQ_NOT_ACCEPTABLE(406,"Not Acceptable."),//SIP
	SIP_PROXY_AUTH_REQ(407,"Proxy Authentication Required."),//SIP
	SIP_REQUEST_TIME_OUT(408,"Request Timeout."),//SIP
	SIP_GONE(410,"Gone: The user existed once, but is not available here any more."),//SIP
	SIP_ENTITY_TOO_LARGE(413,"Request Entity Too Large."),//SIP
	SIP_URI_TOO_LONG(414,"Request-URI Too Long."),//SIP
	SIP_UNSOPPORTED_MEDIA(415,"Unsupported Media Type."),//SIP
	SIP_UNSOPPORTED_URI_SCHEME(416,"Unsupported URI Scheme."),//SIP
	SIP_BAD_EXTENSION(420,"Bad Extension."),//SIP
	SIP_EXTENSION_REQUIRED(421,"Extension Required."),//SIP
	SIP_INTERVAL_TOO_SHORT(423,"Interval Too Brief."),//SIP
	SIP_TEMPORARILY_UNAVAILABLE(480,"Temporarily Unavailable."),//SIP
	SIP_TRANSACTION_NOT_EXISTS(481,"Transaction Does Not Exist."),//SIP
	SIP_LOOP(482,"Loop Detected."),//SIP
	SIP_TOO_MANY_HOPS(483,"Too Many Hops."),//SIP
	SIP_WRONG_ADDRESS(484,"Address Incomplete."),//SIP
	SIP_AMBIGUOUS(485,"Ambiguous."),//SIP
	SIP_BUSY(486,"Busy Here."),//SIP
	SIP_REQUEST_TERMINATED(487,"Request Terminated."),//SIP
	SIP_REQ_NOT_ACCEPTABLE_HERE(488,"Not Acceptable Here."),//SIP
	SIP_REQ_PENDING(491,"Request Pending."),//SIP
	SIP_UNDECIPHERABLE(493,"Undecipherable: Could not decrypt."),//SIP
	//5xx - Server (Standard)
	SIP_SERVER_ERROR(500,"Server Internal Error."),//SIP
	SIP_NOT_IMPLEMENTED_HERE(501,"Not Implemented: The request method is not implemented here"),//SIP
	SIP_BAD_GATEWAY(502,"Bad Gateway."),//SIP
	SIP_SERVICE_UNAVAILABLE(503,"Service Unavailable."),//SIP
	SIP_SERVER_TIME_OUT(504,"Server Time-out."),//SIP
	SIP_VERSION_NOT_SUPPORTED(505,"Version Not Supported:The server does not support this version"),//SIP
	SIP_MESSAGE_TOO_LARGE(513,"Message Too Large."),//SIP
	//6xx - Global (Standard)
	SIP_BUSY_EVERYWHERE(600,"Busy Everywhere."),//SIP
	SIP_DECLINE(603,"Decline."),//SIP
	SIP_NOT_EXISTS(604,"Does Not Exist Anywhere."),//SIP
	SIP_NOT_ACCEPTABLE(606,"Not Acceptable."),//SIP
	//10xx - Base de Datos (Viavansi)
	/* Copyrighted */
	//11xx - XML (Viavansi)
	/* Copyrighted */;

	private final int codigo;
    private final String mensaje;

    CodigoError(int cod, String mensaje) {
        this.codigo = cod;
        this.mensaje = mensaje;
    }

    /**
	 * @return Devuelve el mensaje por defecto.
	 */
	public String getMensaje() {
		return mensaje;
	}

	/**
	 * @return Devuelve el codigo de error asociado.
	 */
	public int getCodigo() {
		return codigo;
	}

    /* (non-Javadoc)
     * @see java.lang.Enum#toString()
     */
    @Override
    public String toString() {
    	return mensaje+"[codigo error:"+codigo+"]";
    }

}