Objetos

febrero 13, 2015
En su forma más general, un programa orientado a objetos es un conjunto de objetos pasándose mensajes para resolver un problema.

Si pensamos a la computadora como 4 objetos: un teclado, un mouse, un monitor y un gabinete, cada vez que apretamos una tecla del teclado o movemos del mouse, el teclado o el mouse le envían un mensaje al gabinete. El gabinete recibe el mensaje y lo procesa y a su vez le envía un mensaje al monitor, que puede ser según el caso dibuja un caracter o cambiá el ángulo de visión de un esapcio 3d.

El problema a resolver puede ser escribir este texto o mover el punto de vista de un personaje en un juego. Los controladores, la cpu y el monitor son los objetos. Las señales eléctricas entre los dispositivos son los mensajes.

¿Cómo hace para hacer todas esas tareas intermedias? No nos preocupa en un principio. Nosotros nos preocupamos por tipear, no cómo llegan los carcteres del teclado al monitor. O bien nos enfocamos en mover el mouse a la velocidad correcta que nos permita observar el paisaje 3d de manera satisfactoria, no los cálculos matemáticos para que ese mundo virtual sea verosímil. A esto de preocuparnos por el qué y no por el como, se lo suele llamar declaratividad. A medida que vayamos adquiriendo más experiencia en el desarrollo de soluciones, vamos a sentirnos tentados a pensar primero el “como” y mirar con desdén el que. Esto hace que nuestras soluciones se vuelvan difíciles de mantener y que de a poco vayamos perdiendo el encanto de lo simple. Por eso conviene siempre no perder de vista el “que” antes de poner el ojo en el “como”.

Los objetos no tienen que ser réplicas de la realidad, alcanza con que sean metáforas que nos permitan resolver un problema de la manera más simple posible y que fáciles de leer cuando alguien o uno mismo tenga que hacer algún ajuste en la solución o solucionar un problema nuevo con estos objetos.

Las metáforas que elijamos van a condicionar profundamente nuestra solución y nuestro estado de ánimo en el futuro.

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?

Pibe, vos tenés que estudiar administración …

noviembre 18, 2013

de ideas. Me parece muy apropiada la frase de acá abajo:

It goes against the grain of modern education to teach children to program. What fun is there in making plans, acquiring discipline in organizing thoughts, devoting attention to detail and learning to be self-critical?
— Alan Perlis, Epigrams in Programming

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!

hope you guess my name

julio 15, 2012

Domingo, materias firmadas a último momento y rasposamente, tps anuales interminables, bajón previo al lunes.

Compasión por el diablo, y por nosotros también.

como llegar a ser el programador ideal

mayo 19, 2012

En la película Hero con Jet Li, en una escena se rebela del ideal al que puede llegar un espadachín. Cabe entender que en esa época se podía vivir de manejar una espada con cierta pericia. El avance de la tecnología llevó a que uno pueda vivir de escribir programas. Salvando grandes distancias, creo que se puede obtener cierto paralelismo entre lo que la peli dice de como se llega a ser un esapadachín ideal y de como se llega a ser un programador ideal.

Va acá una adaptación en inglés, porque me suena más lindo. Pero vale tanto en español como en inglés. El original es en chino mandarín.

Codemanship’s first achievement
is the unity of man and code
Once this unity is attained
even a shell script can solve any requirement
The second achievement is when
the code exists in one’s heart
when absent from one’s hand
One can deploy a full distributed system
even with bare hands
Codesmanship’s ultimate achievement
is the absence of the code
in both hand and heart
The codeman is at peace
with the rest of the world
He vows not to cludge
and to bring peace to mankind

Creo que el primer logro es cuando aprendés decentemente un lenguaje y conocés medianamente los recursos que te da el sistema operativo para hacer casi cualquier programa.

Obtuviste el segundo cuando lográs aprehender el concepto de declaratividad.

Finalmente, podés decir que llegaste al último logro cuando empezás a irte del laburo a la hora que acordaste el día que entraste.

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.

biodiversidad para todos

abril 28, 2012

Entre las muchas cosas que tenemos por acá y que no valoramos porque por ahí no conocemos o porque no quieren que conozcamos, una de las más bellas es la biodiversidad.

Argentina por su extensión cuenta con muchos biomas. Desde desiertos en zonas subtropicales hasta turbales y bosques en la patagonia, sin mencionar nuestro mar. Parte de ese patrimonio enloqueció al propio Charles Darwin.

Nosotros, por cosas de la vida, pasamos de largo y no nos damos cuenta, incluso vivimos amontonados acá en el centro. Bueno, no todos. Existe una gran cantidad de gente interesada en estos temas, coleccionistas de fotos de animales y plantas, biólogos, guardaparques, profesionales del turismo y aficionados a la vida al aire libre que valoran esta riqueza y se esfuerzan en registrarla y que esta tenga el lugar que merece.

Actualmente, estamos analizando y diseñando con unos compañeros de la facultad una herramienta para ayudar al trabajo y la difusión de la biodiversidad en la Argentina y en lo posible colaborar con el desarrollo científico en estos campos. Quien sabe en unos meses tengamos novedades por acá…


Seguir

Recibe cada nueva publicación en tu buzón de correo electrónico.