Posts Tagged ‘desarrollo web’

Internet Explorer 11 y la…

enero 28, 2014

… cadena que identifca el user-agent.

Síntoma: algo anda en Internet Explorer 10 y al actualizar a 11 deja de andar.

Esto se debe a que nuestros humildes programas web tienen que adaptarse a las características de javascript de cada navegador.

La solución más clásica era buscar el substring “MSIE” en el User Agent String.

Internet Explorer 11 no quiere que lo traten como a sus versiones anteriores y no incluye el substring MSIE.

Para eso recomiendan con mucho tino detectar características en vez de substrings.

En el raro caso de que no se pueda, reconocerlo con el substring Trident.

Mientras hacemos los arreglos el modo de compatibilidad nos puede sacar del paso.

En nuestro caso había que bloquear el F5 y el Control-R. La implementación para IE usaba el evento document.onkeydown, mientras que la versión para Mozilla y Chrome usa addEventListener al evento “keypress”.

Con IE11 trataba de hacer el addEventListener a keypress, lo reconocía, pero al hacer F5 a pesar del return false seguía corriendo el evento. En Mozilla/Chrome esto no pasaba. Lo pasamos a document.onkeydown y todo joya. ¡La próxima será MSIE!

La aplicación no la hicimos nosotros, sino un proveedor externo y el cambio tenía que ser lo menos invasivo posible. Fuimos por el Trident.

¿El fin de xAMP?

diciembre 11, 2013

Para no abandonar el vicio estoy haciendo algunas cositas en PHP.

Pero como adquirí vicios estoy tratando de evitar eso de mezclar lógica con renderizado de html. A lo que llegue fue a armar un html bien básico y jQuery y eventos mediante, circunscribo los pedidos al servidor en una capa javascript que gestiona los requests y renderiza el resultado de los response.

Del lado del servidor quedan unos scripts PHP muy sencillos que se concentran en ejecutar la lógica y devolverlos en un formato javascript friendly. Tan reemplazable con servlets + jaxb…

Hace poco compré un librito(sí… es vintage, pero no hay nada más lindo que recibir del correo tradicional el sobre marrón) de manning acerca de Single Page Web Applications. El libro tiene más o menos la misma arquitectura pero la variante que propone es node.js del lado del servidor reemplazando a PHP y jubilar a MySQL por la cada vez más ubicua MongoDB.

Es muy difícil en el mercado rioplatense vender una aplicación que confía sus datos a Mongo…DB, pero parece que las cosas van para ese lado.

¿será el fin de apache, MySQL y PHP?

Xtext codea por vos

noviembre 12, 2013

Buenas. El proyecto final de la carrera de Ing. en  Sistemas que estoy desarrollando es un entorno para enseñar programación orientada a objetos en el que puedo ver los objetos de manera gráfica y darles movimiento y un aspecto.

Es un prototipo todavía, pero con suerte y viento a favor en el mediano plazo va a estar completo,  y quién dice no lo podamos poner a prueba con estudiantes.

Está hecho con Xtext, un framework para desarrollar lenguajes e integrarlos fácilmente a eclipse.

Uno define una gramática, Xtext te genera los elementos para parsear y validar el lenguaje y a partir de ella se puede generar código en el lenguaje que prefiera e incluso construir un intérprete sobre la misma plataforma. HOOPE usa Xtensivamente este framework y otros chiches de la API de eclipse.

Xtext permite generar código java muy fácilmente e integrarlo con las APIs de uso común como JAX-WS o JPA.

En el laburo estoy desarrollando servicios web y tengo que admitir que no siempre es fácil la metodología wsdl-first. Sobre todo porque al que solicita los servicios web le cuesta adaptarse a los wsdl. Pero tampoco es cómodo programar de entrada y anotar con jax-ws. Hay mucho código – andamiaje y puede volverse Vogon Poetry.

Y Xtext andaba en mi cabeza…

Con una gramática muy sencilla:

grammar org.miguelius.ws.Generator with org.eclipse.xtext.xbase.Xbase

generate generator "https://lodemiguel.wordpress.com/ws/WsGenerator"

Service:
	('package' packageName=QualifiedName)?
	('targetNamespace' targetNamespace=STRING)?
	'webservice' name=ValidID '{' operations+=Operation+ '}';

Operation:
	name=ValidID '('
	(params+=FullJvmFormalParameter
	(',' params+=FullJvmFormalParameter)*)?
	')'
	'returns'
	'('
	(returned+=FullJvmFormalParameter
	(',' returned+=FullJvmFormalParameter)*)?
	')';

Como el lenguaje está basado en xbase / jvm, puedo usar un inferrer. El inferrer permite generar código con chequeo de tipos a partir del árbol sintáctico:

   	def dispatch void infer(Service element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
		val requests = new HashMap()
		val responses = new HashMap()
   		// Here you explain how your model is mapped to Java elements, by writing the actual translation code.

   				for (operation : element.operations) {

   						val req = operation.toClass(operation.name + 'Request')
   						acceptor.accept(req).initializeLater[
   							packageName=element.packageName
							for (param : operation.params) {
								members += toField(param.name, param.parameterType)
								val getter = toGetter(param.name, param.parameterType)

								val getterAnnotation=findAnnotation(typeof(javax.xml.bind.annotation.XmlElement),param)
								getterAnnotation.addStringValue("name", param.name)
								getter.annotations+=getterAnnotation

								members += getter
								members += toSetter(param.name, param.parameterType)
							}
   						]
   						requests.put(operation, req)

						req.annotations += findAnnotation(typeof(javax.xml.bind.annotation.XmlRootElement),operation)

   						val resp = operation.toClass(operation.name + 'Response')

						resp.annotations += findAnnotation(typeof(javax.xml.bind.annotation.XmlRootElement),operation)
   						acceptor.accept(resp).initializeLater[
   							packageName=element.packageName

							for (param : operation.returned) {
								members += toField(param.name, param.parameterType)
								val getter = toGetter(param.name, param.parameterType)

								val getterAnnotation=findAnnotation(typeof(javax.xml.bind.annotation.XmlElement),param)
								getterAnnotation.addStringValue("name", param.name)
								getter.annotations+=getterAnnotation

								members += getter
								members += toSetter(param.name, param.parameterType)
							}
   						]
   						responses.put(operation, resp)
				}
   		// An implementation for the initial hello world example could look like this:
   		val wsInterface = element.toInterface(element.name,[])
   		//wsInterface.annotations+=findAnnotation(typeof(javax.jws.WebService),element)
   		acceptor.accept(wsInterface)
   			.initializeLater([
   				packageName=element.packageName

   				val webService = findAnnotation(typeof(javax.jws.WebService),element)
   				webService.addStringValue("name", element.name + "Type")
   				annotations+=webService

   				val soapBinding = findAnnotation(typeof(javax.jws.soap.SOAPBinding),element)
   				soapBinding.addEnumValue("parameterStyle",
   					getTypeForName(javax.jws.soap.SOAPBinding.ParameterStyle, element),
   					'BARE'
   				)
   				annotations+=soapBinding
   				for (operation : element.operations) {

					val responseReference = responses.get(operation).fullName.getTypeForName(element)
					val requestReference = requests.get(operation).fullName.getTypeForName(element)

					val operMethod = operation.toMethod(operation.name, responseReference) [
						val parameter = toParameter(requests.get(operation).fullName.toFirstLower,requestReference)
						val webParam = findAnnotation(typeof(javax.jws.WebParam),operation)
							.addStringValue("name", requests.get(operation).fullName)
							.addStringValue("partName", requests.get(operation).fullName)
						parameter.annotations += webParam
						it.parameters+= parameter
					]
					operMethod.annotations+=findAnnotation(typeof(javax.jws.WebMethod),operation)

   					members += operMethod
   				}
   			])

   	}

Esto está en lenguaje xtend y no soy un especialista (dicho con más que pena que gloria). Admite sendos refactors, por ejemplo mejorar los dispatches del método infer. El pseudcódigo se muy sencillo:

  1. Generar una clase Request y Response por objeto con los parámetros de cada una con sus anotaciones JAXB
  2. Generar una interfaz para el Servicio y anotarla con JAX-WS
  3. Agregar las operaciones y anotarlas con JAX-WS

Esto me genera las clases java y la SEI. Heredo de la interfaz y tengo definido el servicio.

De esta manera, me puedo sentar con el cliente y definir un servicio de una manera comprensible para ambas partes y sin ahondar en detalles.

Supongamos que queremos hacer un servicio web para registrar posts que reciba un título y el contenido y me devuelva el ID del post y la URL.


webservice PostService {

RegistrarPost
(String Titulo, String Cuerpo)
returns
(Integer PostID, String URL)

BuscarPostPorID
(Integer PostID)
returns
(String Titulo, String Cuerpo)

}

Esto construye la interfaz PostService, con los métodos RegistrarPost y BuscarPostPorID. A su vez construye las clases RegistrarPostRequest y RegistrarPostResponse y otro par para BuscarPostPorID. Todo con sus anotaciones y listo para nuestra implementación de JAX-WS lo publique.

Con relativamente poco código tenemos un DSL para generar Web Services en java de manera declarativa y accesible a quién conoce el dominio.

Estoy trabajando en agregar tipos compuestos y listas.

Como sea ya tenemos la primer experiencia con Xtext en protoducción.

¡Hasta la próxima!

Problemas con charset con JSF y messages.properties

mayo 14, 2012

Estoy desarrollando un aplicación web con JBOSS AS 7.1 usando JSF. Este tipo de emprendimientos los hacía usando Spring. Entiendo que Java EE 6 tiene muchas cosas que antes eran características de Spring, por eso me animé al salto.

Todo venía bien (con las marchas y contramarchas propias del self made java ee developer) hasta que tope con un problema de encoding del message.properties.

Parece que por defecto te imprime los carácteres en el locale de la máquina. Mi sistema operativo para mi idioma usa iso-latin-1. Los templates están en utf8, el message.properties está en utf-8. Desastre en puerta.

Googleando un poco me enteré que por cuestiones de implementación, las properties no puede usar código que no estén en el mapa de latin-1.

Una manera de evitar el problema era representar los caracteres especiales con la notación \u####, donde #### es el código UTF del carácter. Esto se podía hacer trabajando con el archivo en utf8 y a la hora de desplegar, convertir el archivo original en código ASCII + \u#### usando la herramienta native2ascii provista con la jdk.

Medio lastimoso.

En la url citada más arriba proponen sustituir la implementación del resource bundle por una que soporte UTF-8. El código lo puede ver en el artículo Internationalization in JSF with UTF-8 encoded properties files. El único cambio que le hice fue usar otra ubicación para el archivo por messages.properties, cambiándola en la constante BUNDLE_NAME = “messages”.

Con eso funcionó de pelos.

Por un momento extrañé a Spring 😛

Armando un servlet desde bien abajo.

mayo 12, 2012

Este artículo de hoy no busca ser una receta de cómo hacer algo en el ambiente laboral. Muchas de estas que vamos a ver las resuelven herramientas como Eclipse, maven, etc. El objetivo es un “estudio” un poco más hondo de lo que pasa desde que escribimos nuestro servlet hasta que llega al servidor y queda corriendo.

El servlet lo vengo prometiendo desde un post anterior. La idea de bajar a la línea de comando surgió de la idea de probar esto de los servlets sin tener el Eclipse ni el Netbeans. Así que estábamos linux, vim, la jvm y yo. Comparto la experiencia porque creo que puede ayudar a alguien que trabaja con java web a entender mejor y saber realmente lo que hacen por nosotros las herramientas.

El ejemplo lo vamos a hacer para Windows esta vez.

¿qué vamos a hacer?

Un contador de palabras. El contador de palabra tiene dos componentes: Un formulario en el que escribimos un texto y un servlet que cuenta las palabras y nos muestra por pantalla el resultado.

Nos va a quedar un a archivo palabras.war, que es la manera en que la especificacion de java empaqueta las aplicaciones web. Ese .war va a tener un formulario html y un servlet.

¿qué necesitamos?

Ganas y:

  • un jdk de 1.5 en adelante.
  • un contenedor de servlets, en este caso tomcat 6 , bajarlo como .zip, no vale usar instalador.
  • un editor de texto.
  • un poco de maña con variables de entorno y scripts .bat.

Conociendo el contenedor de Servlets

Tomcat es el contenedor de servlets de uso más extendido, así que no es mal plan conocer algunas cosas básicas. Es una aplicación java, por lo cuál corre desde una JRE. Desde la versión 5, no es necesaria la JDK. Sin embargo como nosotros vamos a compilar y armar nuestro proyecto a mano, vamos a necesitarla de todos modos.

El paquete zip viene con los siguientes directorios.

apache-tomcat-6.x.x/
  bin/
  conf/
  lib/
  logs/
  temp/
  webapps/
  work/

A vuelo de pájaro: el directorio bin contiene los ejecutables y los scripts de arranque y de apagado.

El directorio conf tiene los archivos server.xml, web.xml y tomcat-users.xml como más representativos. Permiten configurar los puertos que va a usar, opciones de la web que vamos a mostrar, como cual es la página de inicio y los usuarios de algunas aplicaciones.

Lib tiene los jar que usa para trabajar y que van a usar en común las aplicaciones que carguemos. Nos puede dar una mano para compilar.

temp maneja los archivos temporales

En webapps van las aplicaciones. El objetivo es generar el palabras.war y ponerlo en este directorio. Tomcat sólo lo va a descomprimir y poner en marcha.

work es un directorio que usa internamente tomcat donde despliega las cosas.

Lo descomprimimos y vamos al directorio bin y ahí ejecutamos startup.sh. Va a aparecer una ventanita que nos va  informar lo que está haciendo. Una vez que termine informa: Server statup in x ms.

Windows probablemente nos informe que está queriendo acceder a la red. Le decimos que sí. Lo que está pasando es que al ser un servidor, Windows nos avisa que estamos abriendo algo que está escuchando cosas en la red y que otras computadoras pueden acceder. En realidad no es nada grave porque lo estamos usando nosotros sólos y hoy por hoy lo más probable es que estemos detrás de un router, así que si alguien accede, es alguien de la red local, con lo cuál no hay un peligro cierto.

Abrimos el navegador y accedemos a http://localhost:8080.

Deberíamos ver una pantalla donde nos comenta que estamos viendo, aparece el logo de tomcat y todo feliz.

Manos a la obra.

Primero vamos a armar un directorio, y dentro de este vamos a tener la siguiente estructura:

./
  src/
    com/
      palabras/
        controller/
  webapp/
    WEB-INF/
    classes/

El código de la aplicación va a estar en los siguientes archivos:

  • src/com/palabras/controller/ContarPalabrasServlet.java
    Clase java que implementa el servlet contador de palabras.
  • webapp/index.html
    Archivo HTML que contiene un formulario que usa al servlet contador de palabras.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
  <HEAD>
    <TITLE>Jugando con palabras</TITLE>
  </HEAD>
  <BODY>
    <H1>Jugando con palabras</H1>
    <P>Aplicaci&oacute;n muy sencilla basada en servlets para contar palabras.</P>
    <FORM METHOD="POST" ACTION="ContarPalabras">
      <FIELDSET>
        <P>Escrib&iacute; o peg&aacute; un texto ac&a abajo:</P>
        <TEXTAREA name="texto" ROWS="5"></TEXTAREA>
        <BR/>
        <INPUT TYPE="SUBMIT" value="A contar!" />
      </FIELDSET>
    </FORM>
  </BODY>
</HTML>

Acá empiezan las complicaciones. Hay que compilar y generar el archivo .war.

De estas tareas normalmente se encargan eclipse, ant o maven. Hoy vamos a tratar de hacerlo nosotros.

Los primeros ejemplos que uno compila en java no usan nada más que las clases propias y las clases que ya vienen en rt.jar, o la biblioteca estándar de runtime. Por eso casi no jugamos con el classpath.

package com.palabras.controller;
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
public class ContarPalabrasServlet extends HttpServlet {

	public ContarPalabrasServlet() {
		super();
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		manejarRequest(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		manejarRequest(request, response);
	}

	private void manejarRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	PrintWriter out = response.getWriter();
		out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">");
    	out.println("<HTML>\n");
		out.println("\t<HEAD>\n");
    	out.println("\t\t<TITLE>Contar Palabras</TITLE>\n");
    	out.println("\t</HEAD>\n");
    	out.println("\t<BODY>\n");
		out.println("\t\t<H1>Contar Palabras</H1>\n");

		String texto = (String )request.getParameter("texto");
		if (texto == null || texto.isEmpty()) {
			out.println("\t\t<h2 style=\"color:red;\">Debe ingresar un texto, sino no hay mucho que contar.</h2>\n");
		} else {
			out.println(String.format("\t\t<p>El texto se compone de %d palabras</p>", texto.split("/\\s/").length));
			out.println(String.format("\t\t<textarea readonly=\"true\">%s</textarea>", texto));
		}
    	out.println("\t</BODY>\n");
    	out.println("</HTML>\n\n");
    	out.close();
	}

}

Acá la cosa es un poco distinta. Si queremos compilar nuestro Servlet vamos a fracasar lastimosamente porque no encuentra la clase HttpServlet. Esto es porque la clase no está ni entre nuestro ni entre la biblioteca estándar de java. Bueno, esa biblioteca viene incorporada en el directorio lib/ que mencionábamos más arriba, y servlet-api.jar.

Para compilar, entonces vamos a tener que indicar que el classpath incluya el directorio de tomcat/lib con la opcion –classpath o -cp.

Otra cosa que nos va a pasar es que el .class va a quedar en el mismo directorio de la clase, y nosotros queremos que vaya en una ubicación especial respetando la jerarquía de directorios que corresponde al paquete deonde creamos el servlet (com.palabras.controller). El compilador de java nos da una opción -d RUTA para compilar y dejar los .class con la estructura de subdirectorios. Si compilamos el servlet con la opción -d C:\, notaríamos que aparece en C:\ un directorio com, adentro del último uno llamado palabras y así.

¿Pero, a dónde?

Conociendo los archivos war

El war es un archivo comprimido que adentro contiene una serie de archivos y directorios. La organización interna no es caprichosa y responde a una especificación.

Vamos a trabajar con la especificación 2.4. Las más nuevas tienen una serie de simplificaciones que vamos a obviar para retormarlas cuando estemos un poco más duchos.

El war que vamos a armar tiene la siguiente pinta:

./
  WEB-INF/
    classes/
       com/
         palabras/
           controller/
              ContarPalabrasServlet.class
    web.xml
  index.html

El directorio WEB-INF tiene información que la indican al contenedor características del proyecto, las bibliotecas que la aplicación usa y las clases que componen a la aplicación. Nuestro proyecto es tan sencillo que le alcanza sólo con la carpeta classes.

Ahora que sabemos donde, podemos compilar:

javac -cp c:\apache-tomcat-6.0.35\lib\servlet-api.jar \
      -d webapp\WEB-INF\classes \
      src\com\palabras\controller\ContarPalabrasServlet.java

El parámetro -d webapp\WEB-INF\classes es el que le indica que guarde el resultado de compilar en el directorio WEB-INF\classes.

El archivo web.xml es el descriptor de implementación y es el encargado de indicarle al contenedor de servlets cual es la página de inicio, el nombre con el que tiene que desplegar el proyecto, el mapeo de urls que no correspondan a archivos dentro del war. Si nos fijamos en el formulario dentro de index.html hacemos referencia a una action ContarPalabras, pero no existe ningún archivo que se llame así.

Para que tomcat pueda atender al pedido de ContarPalabras tenemos que indicárselo en el web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="palabras" version="2.4" 
	xmlns="http://java.sun.com/xml/ns/j2ee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	<description>
		Jugando con palabras
	</description>
	<display-name>palabras</display-name>
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
	</welcome-file-list>
	<servlet>
		<description>
			Servlet para contar palabras
		</description>
		<display-name>ContarPalabras</display-name>
		<servlet-name>ContarPalabrasServlet</servlet-name>
		<servlet-class>com.palabras.controller.ContarPalabrasServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>ContarPalabrasServlet</servlet-name>
		<url-pattern>/ContarPalabras</url-pattern>
	</servlet-mapping>
</web-app>

Bueno, acá hay muchas cosas. El tag welcome-fil-list, contiene una lista de archivos que pueden ser interpretados por el contenedor como archivo por defecto cuando piden la aplicación.

El tag servlet define un servlet, el display-name es el nombre que nos muestra en el servidor, el servlet-name es un identificador del servlet en este contexto y servlet-class es la clase que implementa el servlet. En nuestro caso com.palabras.controller.ContarPalabrasServlet. Hay que poner el nombre completo (FQDN), para que pueda resolverlo buscando en el directorio WEB-INF/classes.

Por último <servlet-mapping> es el que le dice al contenedor que servlet debe resolver que la url del request.

En Java EE 6, la definición y mapeo de servlets se realiza mediante annotations, una de las razones por la cuál el archivo web.xml es optativa.

Ahora que ya tenemos todo armado en el directorio webapp llegó la hora de empaquetarlo y desplegarlo (deployarlo).

Esto se hace usando el comando jar que viene con la jvm. jar nos permite armar paquetes como los .jar, los .war, .ear, etc.

Nos vamos al directorio donde creamos los directorios src y webapp y ejecutamos:

jar cf palabras.war -C webapp .

Nos fijamos en el directorio y tenemos un archivo palabras.war. Podemos abrirlo con WinRar y verificar que tiene lo que esperamos.

Poner en marcha la aplicación será tan difícil como copiar el archivo palabras.war en el directorio webapps dentro del directorio del tomcat.

Tomcat detecta la novedad en el filesystem y realiza el despliegue de la aplicación. Cuando termina, nos lo notifica.

Abrir el navegador e ir a http://localhost:8080/palabras

Si todo fue bien, felicitaciones! Cualquier cosa acá abajo se contestan dudas.

¿qué es esto de los servlets?

enero 12, 2012

Mi inmersión al mundo java web ocurrió hace unos años ya, pero recuerdo que yo andaba medio perdido con muchos nombres nuevos y con poca idea de cómo se hacían las cosas por ese alocado lugar.

Hoy un poco más cascado puedo ordenar algunas ideas y contar un poco lo que aprendí.

Antes que nada responden a una especificación como casi todo en java.

Un servlet es un componente java que permite generar contenido dinámico y que corre en el contexto de contenedor de servlets. Los servlets que usamos para programar web son los HTTP Servlets. Estos corren en un contenedor -que es parte de un servidor web o de un servidor de aplicaciones y que se encarga de manejar la comunicación con el cliente usando el modelo de Petición / Respuesta. Un ejemplo de contenedor de servlets es apache tomcat.

El contenedor suele tener un archivo descriptor de despliegue: el archivo WEB-INF/web.xml.

En este archivo mapeamos las URL con los servlets que vamos creando, configuración de la sesión y otras cosas como definición de filtros y etc.

A diferencia de otras tecnologías, donde se crea todo un proceso por cada solicitud del cliente, un servlet corre en un hilo. Esto genera menos carga para el servidor, por lo que se supondría que es más rápido.

El contendor maneja su ciclo de vida, que empieza llamando al método init(ServletConfig) e inicializa nuestro servlet. Por cada petición que recibe, invoca al método service(ServletRequest, ServletResponse). Finalmente destroy() es invocado cuando el contenedor decide descargarlo y es el momento para liberar recursos.

Los HttpServlet en particular nos abstraen de manejar qué mensaje HTTP implementando el método service y dejándonos a nosotros implementar los distintos mensajes como GET, POST, DELETE y PUT mediante doGet, doPost, doDelete y doPut. Estos a su vez reciben como parámetro los objetos de clase HttpServletRequest y HttpServletResponse. El servlet trabajará con el contexto provisto por el Request y escribirá en el Response los resultados de su ejecución.

En el próximo capítulo vamos a implementar un servlet muy sencillo que recibe una frase y cuenta la cantidad de palabras. Este implementa los métodos de HTTP, POST y GET. Si no recibe nada para contar,  explica el uso y provee un form, si recibe algo directamente muestra el resultado.

¡Hasta la próxima!

Incluir videos en SPIP

julio 9, 2008

Hace mucho tiempo que mis SPIP adictos me vienen pidiendo como incorporar videos en sus sitios.

Por cuestiones de ancho de banda, y también promocionales, es conveniente tenerlos en youtube. La única salvedad que tiene es si youtube está bloqueado en el lugar donde queremos ver. Para solventar esto se puede programar un proxy para youtube (perdiendo las ventajas antes mencionadas) o bien ver los videos fuera de horario de oficina.

El método es sencillo: se los agrega como un documento adjunto.

  1. Subimos el video a youtube.

  2. Una vez que tenemos el video en youtube debemos observar la dirección que youtube le asigna:

    http://www.youtube.com/watch?v=OlLT7-7FUiU

    Para esta dirección nuestra dirección de carga será:

    http://www.youtube.com/v/OlLT7-7FUiU

    En el Cuadro “AÑADIR DOCUMENTO” hacemos clic sobre desplegable “Subir desde tu ordenador”. Esto nos muestra otra caja de texto que tiene solamente el contenido “http://”. Nosotros lo reemplazamos con la dirección de carga “http://www.youtube.com/v/OlLT7-7FUiU” y apretamos “Elegir”.

  3. Se cargará un bloque nuevo con título “OlLT7-7FUiU” y en la parte inferior de este bloque debemos asignarle Dimensiones (0 x 0 por defecto). Nosotros le asignamos 425 x 344 píxeles. Este paso es tan importante como el anterior. No hay que omitirlo. Si quisiéramos cambiarlo de tamaño basta con ajustar el 425 x 344 a otra relación. Es el alto debe ser aproximadante 81% del ancho.

Con esto tenemos el documento adjunto. Para que aparezca en la página solo resta incluir la etiqueta <embXXX> en el editor de texto de nuestro documento, donde XXX es el número asignado al video.

¡Voilá!

¡Feliz día, Patria!

Crear PDFs del lado del servidor: iText y FPDF

marzo 7, 2008

Armando un form super largo que después tenía que salir por impresora se me presentó la dicotomía: OpenXML o PDF.

Necesitaba soporte para headers y paginación. Que el documento de salida fuera editable no era necesario.

Estaba en .NET, razón por la cuál OpenXML hubiera sido la opción más razonable. A poco de andar terminé encontrando que utilizar Word a través de COM no era nada recomendable del lado del servidor. Necesitaba entonces una biblioteca que maneje el tema. Me encontré con una paga a la cuál no voy a linkear, porque le sobran links de entrada. Microsoft ofrece una biblioteca para generar OpenXML pero genera documentos para Office 2007. No todo el mundo tiene Office 2007, razón por la cuál el camino del OpenXML se iba cerrando. La última opción era generar el doc, guardar como Office XML 2003 y parsear el documento mediante XML o tags. El documento terminaba pesando 900 KB, inaceptable para un ambiente con concurrencia.

Bueno, hubo que tomar el camino del PDF…Yo había hecho algo parecido en PHP con una biblioteca que se llama FPDF. Es una clase PHP 4.0 sencilla pero muy potente para generar PDFs. Lo bueno es que hay un montón de ejemplos en su sitio y hay documentación en español. Lo malo es que es un poco tosca, pero es muy fácil de extender. El enfoque es como trabajar con un lienzo (canvas para la muchachada) donde vamos dibujando nuestras genialidades.

El drama era que había que conseguir algo parecido y allà GPL para .NET. Me encontré con iTextSharp. iText es una biblioteca para generar PDF en java. Muy completa, también es un lienzo pero tiene estructuras como párrafo, frase y pedacito (Paragraph, Phrase y Chunk) y una completa implementación de tablas. Esto permite simplificar muchas tareas que en FPDF me costaban bastante. La biblioteca está muy bien hecha y facilita mucho trabajo. A su vez permite acceder al contenido del pdf a bajo nivel de una manera muy sencilla.

Por si fuera poco hay un tutorial para iTextSharp muy sencillo y elocuente para el desarrollador en apuros, al igual que en FPDF. Lo único que se añora es que no esté en español.

Los autores Bruno Lowagie y Paulo Soares(responsable del port a .NET) han hecho un gran trabajo. Hay un libro muy interesante llamado iText in Action. El libro a través de un caso ficticio -pero muy parecido a lo que pasa en realidad- va cubriendo todas las funcionalidades de la biblioteca y trae piezas de código muy interesantes.

En esencia la biblioteca nos permite generar un pdf en 5 pasos básicos:

  • instanciar un objeto Document
  • generar una instancia del PdfWriter y asociarla a un canal (stream)
  • abrir el documento
  • insertar el contenido
  • cerrar el documento

Nuestro trabajo será esencialmente generar el contenido, porque todo lo demás ya nos los provee la biblioteca.

A su vez tiene un modelo de eventos para la documento, página y tabla. De esta manera podemos generar encabezados y pies de página dinámicos, centralizar los estáticos, etc.

La verdad es que fue una grata sorpresa encontrar la biblioteca esta. Mi solución terminó siendo un HttpHandler que genera los pdfs con iTextSharp. El archivo pesa 40 KB. El mundo ha sido salvado nuevamente. Diós está en el Cielo, todo está en en la Tierra.

ASP.NET MVC

enero 19, 2008

Anoche fui a una TechNight de Microsoft donde presentaron ASP.NET MVC. Los chicos que dieron la exposición estuvieron muy bien, y que haya habido cerveza y papas fritas a la salida me pareció un gran gesto. Eso y los ojos de una muchacha que andaba dando vueltas por ahí, azules como el cielo de este hermoso día.

Mi pregunta era como habían hecho las cosas… No las hicieron mal, solo que las hicieron igual… ¡Ejemplo del blog con comentarios incluido!

Igual a Ruby on Rails, a Monorail, a CakePHP, a todos los frameworks MVC, pero con las tecnologías de VS 2008. Como ORM utilizan LINQ, como API para Sindicación usan WCF, etc.

Algo muy positivo es que los módulos que componen el modelo se comportan como módulos realmente y son intercambiables.

Tiene un router de urls, expresiones regulares para validar. ¡Está todo!

Tal vez lo más interesante sea en que cada parte sea implementada como una interfaz, permitiendo implementar las propias, hacer mock-objects, utilizar sistemas de templates como los de MonoRail o implementar el propio sistema de Ruby On Rails. Es muy flexible en eso. Esto para integrar aplicaciones ya desarrolladas es un golazo.

Otra ventaja -que al programador asp.net medio no le parece tal- es que se van el viewstate y el postback. ASP.NET depende mucho de estas cuestiones y ahí es donde se complican la mayoría de las páginas. Haber transportado el esquema de eventos de Visual Basic a la web es algo que ayuda mucho a acortar la curva de aprendizaje para pasar de una tecnología a otra, pero los dolores de cabeza empiezan cuando hay que hacer cosas en AJAX, o necesitamos manosear el DOM desde javascript. Se puede calcular o directamente obtener el id del DOM de los controles. El drama es cuando estos son generados como ItemTemplates, hay que hacer alguna chanchada. El esquema es bueno en una aplicación de escritorio, pero en web es muy pesado. Esto lleva a que todos los controles que dependían del viewstate y del post-back hayan quedado, bueno, “deprecated”. Tendrían que haber visto como se puso la monada cuando los chicos tuvieron que avisar que el GridView no iba más. AJAX.NET también se ve comprometida.

Tranquilos muchachos, están los Helpers de la UI para generar nuestros nuevos controles. En vez de Viewstate usamos el cache del lado servidor. Es programar un poco más, pero podemos armar nuestro propio Viewstate usando la Cache. Y ganamos obteniendo páginas y sesiones más livianas.

Con .NET 3.5 hay variables tipadas dinámicamente, saludando al variant de VB. Sinceramente, si no era porque las variables NO empezaban con $, hubiera jurado que estaba viendo código PHP y templates de CakePHP en Visual Studio 2008.

Otra cosa es que IIS 7 ya permite Rewrite Rules o algo por el estilo. Lo que nos permite hacer la magia de las urls amigables a la intuición del usuario y a los buscadores.

La verdad es que me parece muy bueno que ASP.NET provea la posibilidad de trabajar con MVC, al margen de que yo lo haga. Le da al desarrollador un enfoque nuevo muy útil en varios escenarios.

Espero que le den para adelante, porque se va a ganar mucho en flexibilidad y legilibidad del código. Pero tal vez lo mejor es que trabajar con MVC nos ayuda a identificar mejor los requerimientos de nuestra aplicación y trabajar en función de ellos. Después si tiene que salir en ATOM, XHTML o código morse ya es problema de la vista y sus helpers. Nosotros tenemos nuestro controlador que hace el trabajo importante.

Yo voy a seguir firme junto a PHP5, SPIP y CakePHP en trabajo independiente, dado que no tengo un IIS7, ni plata para comprar un módulo ISAPI de redirección para IIS6 (otra cosita que tuvieron que contar los chicos), pero ASP.NET MVC sería mi “weapon of choice” a la hora de trabajar en web con .NET.

Problemas con Charset y PHP

octubre 9, 2007

Los problemas de charset surgen de dos cuestiones:

  • Estoy abriendo una fuente utf-8 y mi salida se ve en iso-8859-1
  • o bien el opuesto: iso-8859-1 la fuente, salida utf-8

Vamos a “simular” que abrimos un archivo XML y tenemos problemas con el charset.

Primer caso

Diagnóstico: Por lo general el primer caso se da cuando veo en vez de eñes y acentos dos caracteres. Suelen ser un à y algo más. En el ejemplo el archivo XML estaría codificado en utf-8 (caso más común) y nuestra página se ve en iso-8859-1

Solución: La fuente está viniendo en utf8 y necesito pasarlo a Latin-1. Esto se hace con la función utf8_decode().

$origen = "http://algunblog/feed/";

//CURL mediante o file_get_contents
//En este caso hacemos la conversion de utf-8
//a iso-8859-1
$contenido = utf8_decode(file_get_contents($origen));

$xml = simplexml_load_string($contenido);
//"masajeamos" el contenido del XML

Segundo caso

Diagnóstico: En vez de caracteres especiales vemos unos signos de interrogación o cuadraditos con números. Esto significa que no puede traducir el caracter a alguno Unicode porque está “mal formado”.

Solución: Hay que convertir nuestra cadena a utf-8 mediante la función utf8_encode().

$origen = "http://algunblog/feed/";

//CURL mediante o file_get_contents
//En este caso hacemos la conversion de iso-8859-1
//a utf-8
$contenido = utf8_encode(file_get_contents($origen));

$xml = simplexml_load_string($contenido);
//"masajeamos" el contenido del XML

Estos son los dos casos básicos. Desde ya que esto tiene una explicación un poco más teórica, pero que vamos a abordar en otro post o tal vez le dediquemos una página. Por ahora con esto ya podemos solucionar muchos problemas.

Cuando trabajemos con bases de datos también tenemos que tener en cuenta estas consideraciones. Tenemos ventajas además, por lo general nos permite seleccionar el encoding de la conexión. El parámetro suele llamarse “charset”.

Mi intención es fundar la SALPICADA (Sociedad Argentina por la Lucha contra Problemas Indescifrables de Charset Accediendo a Datos y Archivos) para investigar el tema, capacitar y ofrecer ayuda. Evitemos que nuestras páginas terminen SALPICADAs por feos caracteres que hacen los textos menos legibles.

Cualquier duda, acá estoy.