Multitactil TFT
Viernes, 17 de Febrero de 2006Una pantalla TFT multitactil. El futuro de la interacción humana con los ordenadores, desde luego.
Ver video en http://www.youtube.com/?v=iVI6xw9Zph8
Visto en Vic Divecha’s Tech Blog via yonkis
Una pantalla TFT multitactil. El futuro de la interacción humana con los ordenadores, desde luego.
Ver video en http://www.youtube.com/?v=iVI6xw9Zph8
Visto en Vic Divecha’s Tech Blog via yonkis
El sistema de internacionalización de Webwork es muy sencillo e interesante. Sin embargo, hoy le he echado en falta algo que parece que se les ha pasado por alto a sus creadores. Vamos a ver que és y como corregirlo.
Es fácil mostrar un literal internacionalizado desde JSP o Freemarker. Para hacerlo sólo hay que utilizar la etiqueta <ww:text> así:
<ww:text name="mensajes.error.email"/> <!-- O desde Freemarker --> <@ww.text name="mensajes.error.email"/>
Esta etiqueta se encargará de buscar en el correspondiente properties de nuestro locale actual la clave “mensajes.error.email” para así mostrar su valor en el idioma correcto. Hasta aquí todo correcto.
Pero, ?qué pasa con los atributos label de nuestras etiquetas para los formularios? Pues que se les ha olvidado poder internacionalizarlos, por lo que no se traducen, sino que se muestran literalmente tal y como los hemos escrito en el atributo label de la etiqueta.
Por ejemplo, el siguiente código:
<ww:textfield label="Introduzca usuario" name="login" size="30"> <!-- O desde Freemarker --> <@ww.textfield label="Introduzca usuario" name="login" size="30">
generará un HTML más o menos parecido al siguiente:
<label for="register_user_login" class="label">Introduzca usuario:</label> <input type="text" name="user.login" size="30" value="admin" id="register_user_login"/<
Es decir, nos genera una etiqueta <label> muy bonita, pero inútil, ya que su contenido es literal y no se puede internacionalizar, por lo que podemos resumir que no nos sirve para nada.
Lo ideal sería poder utilizar un código como este:
<ww.textfield label="forms.labels.introduzcalogin" name="login" size="30" >
y que la etiqueta buscara en el properties de nuestro locale actual la clave “forms.labels.introduzcalogin” para mostrar su valor internacionalizado. Bueno, pues para que esto ocurra, solo hay que modificar las siguientes plantillas (que se encuentran dentro de nuestro webwork.jar):
Buscar la siguiente ocurrencia:
${parameters.label?html}
para sustituirla por esta otra:
<@ww.text name="${parameters.label}"/>
Y con esto ya podemos utilizar, tranquilamente, cualquier etiqueta de formularios que utilice el atributo label para que lo muestre de manera internacionalizada.
Si alguna vez os habíais preguntado porque las etiquetas <UL> y <LI> muestran la información con una indentación y unos puntos gorditos tiene facil respuesta: porque así viene definido en el CSS por defecto de nuestros navegadores.
Si no nos gusta este formato o simplemente queremos utilizar estas etiquetas UL y LI para otros fines, podeis probar con este código en vuestra hoja de estilos CSS:
ul, li {
list-style-type:none;
padding:0px;
margin:0px;
}
Por ejemplo, un uso práctico, muy útil (es un menú desplegable) y super sencillo (solo es HTML y CSS, nada de Javascript) lo tenéis aquí mismo:
CSS horizontal navigation list
Es bastante útil llamar a los métodos de las acciones directamente. Es decir, en vez de utilizar llamadas del tipo :
/app/User.action
Llamamos a un método directamente, así:
/app/User!create.action
Ahora bien, ?Qué sucede si, desde otra acción, deseamos encadenar (con un resultado type=”chain”) el resultado de una accion con otra, llamando a un método en concreto?
Por ejemplo así:
<action name="User" class="si.web.action.admin.UserAction">
<result type="chain" name="success">
<param name="actionName">User!list</param>
</result>
</action>
Pues que obtendremos un bonito error. WebWork no encuentra nuestra accion User!list porque, en el momento de buscarla, no quita el metodo del nombre de la acción. Es decir, no busca la accion “User” sino la accion “User!list”, y precisamente con ese nombre no existe. Pero tiene facil solución.
Hace ya unos dias que he reportado este bug en el Jira de Webwork pero hasta el momento no me han hecho mucho caso. Por si a alguien le pudiera interesar, se corrige así:
Tenemos que modificar la clase om.opensymphony.xwork.DefaultActionProxy.java
Para ello nos bajamos el código fuente de la versión de WebWork que estemos utilizando (a ser posible la última, aunque nunca se sabe), y metemos la clase en nuestro proyecto para poder modificarla. Del webwork.jar que utilicemos para desplegar, eliminamos la clase DefaultActionProxy.class, de esta manera nos aseguramos que solo se utilizará la que está corregida en nuestro proyecto por nosotros.
Buscamos el siguiente fragmento de código e insertamos las lineas que están entre los comentarios // START PATCH y // END PATCH
protected DefaultActionProxy(String namespace, String actionName, Map extraContext, boolean executeResult, boolean cleanupContext) throws Exception {
this.cleanupContext = cleanupContext;
if (LOG.isDebugEnabled()) {
LOG.debug("Creating an DefaultActionProxy for namespace " + namespace + " and action name " + actionName);
}
// START PATCH
int posExcl = actionName.indexOf("!");
if (posExcl > -1) {
this.method = actionName.substring(posExcl+1);
actionName = actionName.substring(0, posExcl);
}
// END PATCH
this.actionName = actionName;
this.namespace = namespace;
this.executeResult = executeResult;
this.extraContext = extraContext;
Lo único que hace el parche es asegurarse de eliminar el método del nombre de la acción, para que en la búsqueda no falle.
Una de las muchas cosas que agradezco a Webwork es haber conocido a Freemarker. Este motor de plantillas es realmente potente y se integra completamente con Webwork.
Sin embargo, hay todavía algunas incompatibilidades cuando usamos a la vez Webwork/Freemarker y JSP.
1. Jsp desde Freemarker
Por un lado vemos en la documentación de Freemarker que es posible importar taglibs y utilizarlas desde nuestras plantillas. Esto permite eliminar nuestra dependencia a los JSPs si estamos acostumbrados a utilizar ciertos taglibs.
Para esto solo tenemos que utilizar lo siguiente en nuestras plantillas ftl:
<#assign bean=JspTaglibs["/WEB-INF/struts-bean.tld"]>
Y ya podemos utilizar las etiquetas con la sintaxis:
<@bean.message key="welcome.title"/>
Pero esto es la teoría y lo que dice la documentación de Freemarker, porque en la práctica, y solo cuando utilizamos Freemarker desde Webwork, no funciona. Es un bug conocido que, creo, están intentando arreglar (digo creo porque el bug está reportado en el foro de Webwork y en el jira de Opensymphony desde Octubre del 2005 y a fecha de hoy no se ha arreglado todavía).
2. Freemarker desde Jsp
Por otro lado, tenemos la integración a la inversa: podemos utilizar desde nuestros JSPs plantillas ftl incrustadas. Freemarker incluye un taglib, con solo una etiqueta para este fin. Para utilizarla solo tendremos que añadir lo siguiente en nuestro JSP:
<%@ taglib prefix="fm" uri="freemarker" %> codigo JSP <fm:template> ?codigo freemarker? </fm:template>
?Y funciona! La integración JSP-Freemarker es correcta.
3. Freemarker desde Jsp con Webwork
Cuando utilizamos Freemarker desde Webwork directamente, Webwork crea un "modelo" con todos los objetos de Webwork necesarios que utilizaremos desde nuestra plantilla ftl. Este modelo incluye el stack OGNL, el Action del que venimos, el request y el response (mirad el Variable resolution de la documentación de Freemarker para Webwork).
Pero, ?qué pasa cuando utilizamos Webwork, redirigimos la salida de nuestra acción a un JSP, y desde este JSP utilizamos Freemarker con la etiqueta <fm:template>?
Pues que este modelo no está, ya que la etiqueta que utilizamos esta desarrollada por el equipo de Freemarker y no por Webwork, por lo que este modelo que estamos acostrumbados a utilizar no existe.
O sea, ya no podemos utilizar en nuestro ftl incrustado ${actionbean.atributo} para referirnos a los beans de nuestras acciones como lo hacíamos cuando utilizábamos las plantillas ftl desde Webwork directamente.
?Y cuál es la solución? Modificar el código del taglib y modificar el dispatcher de JSPs de Webwork ligeramente para que incluya este modelo.
Estas son, punto por punto, las modificaciones que hay que realizar.
1. Crearemos en nuestro proyecto una clase dipatcher como la siguiente:
package freemarker.ext.jsp;
import com.opensymphony.webwork.dispatcher.*;
import com.opensymphony.webwork.*;
import com.opensymphony.xwork.*;
import javax.servlet.jsp.*;
import javax.servlet.http.*;
public class ServletFreemarkerDispatcherResult extends ServletDispatcherResult {
public static String REQUEST_ID = "ServletFreemarkerDispatcherResult.ActionInvocation";
public void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {
PageContext pageContext = ServletActionContext.getPageContext();
if (pageContext == null) {
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute(REQUEST_ID, invocation);
}
super.doExecute(finalLocation, invocation);
}
}
Esta clase solo hereda de ServletDispatcherResult para poder añadir el Action actual como atributo del request, que servirá para que la etiqueta modificada pueda crear el modelo correcto a partir del Action. Después simplemente llama al método doExecute() de la clase padre, por lo que el funcionamiento sigue siendo es el mismo.
2 Modificamos nuestro xwork.xml para redefinir el result-type "dispatcher" al nuevo que acabamos de crear.
<result-types>
<!-- result-type name="debug" class="si.web.result.DebugResult" default="false"/-->
<result-type name="dispatcher"
class="freemarker.ext.jsp.ServletFreemarkerDispatcherResult"
default="true"/>
</result-types>
3 Creamos nuestra nueva etiqueta modificada
El código original que no es necesario está solamente comentado. El cambio consiste en eliminar la creación del objeto "root" (el modelo) con un SimpleHash() y lo sustituimos por el resultado del método createModel() (cuyo código está sacado del propio Webwork, cuando utilizamos el result de Freemarker directamente). Para crear este modelo, es necesario el Action actual, el cual nuestro dispatcher modificado se ha encargado de dejar en el request. Utilizamos este Action para llamar a FreemarkerManager.getInstance().buildTemplateModel(), el cual es el que realmente crea el modelo.
4 Modificamos el taglib para que utilice nuestra nueva etiqueta.
<tag>
<name>template</name>
<tagclass>freemarker.ext.jsp.FreemarkerWebworkTag</tagclass>
<bodycontent>tagdependent</bodycontent>
<info>Allows evaluation of FreeMarker templates inside JSP</info>
<attribute>
<name>caching</name>
<required>false</required>
</attribute>
</tag>
Y con todo esto ya podremos utilizar nuestras plantillas ftl dentro de nuestros JSP accediendo al modelo de beans de Webwork.
Los lectores de este humilde blog se habrán fijado que hace un tiempo que posteo poco o muy poco. Es verdad, tengo el weblog un poco abandonado, pero todo tiene su explicación.
He acabado los exámenes y ahora tengo un poco más de tiempo libre, así que he decidido hacer un desarrollo por mi cuenta. Ya que en mi trabajo no programo (soy administrador de sistemas J2EE), tengo que programar fuera de horas de oficina y buscarme el qué picar yo mismo.
Estuve un tiempo pensando qué hacer, como una comunidad para desarrolladores freelance y alguna otra cosa más que me rondó por la cabeza. Llegué a hacer incluso el modelo de datos pero al final no cuajó nada. La verdad es que ya está todo inventado y no se me ocurría nada interesante para mi, ni útil para internet.
Por otro lado, en el trabajo todo el mundo estaba de vacaciones (esto fue en navidad), no había casi nadie y teníamos bastante tiempo libre. Estuvimos buscando algún juego en red pero todos eran demasiado poco discretos. Así que pasamos a los juegos Web, pero era imposible acceder a ninguno, ya que estaban todos capados por el fulminante proxy que todo lo capa. Imposible en la ofi.
Así que se me ocurrió que podía bajarme algún juego open source e instalarlo en mi máquina para poder jugar todos. Me recorrí sourceforge.net en busca de algún juego divertido que fuera web (así no parecía que jugabas, sino que estabas navegando, que es menos reprobable) y que estuviera basado en turnos (ya que para poder jugar a lo largo del día en la oficina no se puede jugar en tiempo real claro está: imagínate que te levantas un rato o te pones hacer algo y de repente ?te fulminan!). Todos los juegos Web estaban basado en turnos y encontré bastantes juegos, la mayoría en fase alpha o beta, pero algunos ya acabados. Me fije que todos estaban hechos en PHP, salvo uno, Techstrike, que estaba desarrollado en Java, pero todavía estaba en fase alpha y no se podía jugar.... Pero... de repente, la emoción surgió dentro de mi. Pensé "si no hay un solo juego online hecho en Java, entonces.... tenía que hacer uno!"
Todos los que me bajé requerían un montaje que no podía hacer fácilmente en la oficina: postgres o mysql y Apache con php. Si, bueno, podía montar mysql, Apache y php bajo Windows, pero no me apetecía demasiado. Al final pasó el tiempo y no conseguimos jugar a ninguno. Pero no pasaba nada, yo al menos había conseguido algo bueno: sabía que tenía que desarrollar. Un nuevo reto, mucho más complicado y divertido que hacer un portal o lo que sea: Un juego multigador online de estrategia basado en turnos. Técnicamente un web-based, turn-based MMOG (Massively Multiplayer Online Game). Saber que hay gente que esta jugando a tu juego y que disfruta con él era un aliciente genial para hacerlo lo mejor posible.
En casa decidí buscar más juegos online basados en turnos y empecé a jugar, no para divertirme, sino para aprender como son. Encontré cosas como Ferion, Travian, Ogame, Criminapolis, Tradelair o Earth 2025. Jugué y leí sobre ellos hasta tener una idea de cómo estaban hechos por dentro. Los que más me gustaron fueron los juegos de estrategia espacial, así que ya tenía donde inspirarme. El que más me gustó, por su complejidad fue Ferion. Os recomiendo jugarlo y también leer manual.
Además el desarrollo del juego serviría para utilizar algunas tecnologías Java que desde hace tiempo conozco pero que nunca he llegado a utilizar. Jamás me llegó a gustar del todo Struts, así que tras investigar y probar sobre otros motores MVC, hubo uno que me encantó: WebWork, asi que ese será el motor MVC de mi juego. Para la capa de presentación, nada de JSPs, gracias a que Webwork ya lo trae incluido, utilizaré Freemarker, un flamante motor de plantillas tan potente como Velocity pero, para mi gusto, mucho más cómodo y practico. Ya os contaré cosas sobre Freemarker y Webwork, estoy muy contento con ellos y creo que serán un estandar a partir de ahora en mis desarrollos.
Además, quería unirlo todo con un poco de Inversion Of Control, y como el propio IoC container que incluye WebWork está "deprecated", nada mejor que Spring para ello. Y para la capa Web, lo que ahora está en boca de todos: Ajax. Aunque para esto, como no me corre prisa, todavía no hay ninguna librería o framework decidido. Aunque por ahora me ha gustado Ajax Any Where. Como servidor de aplicaciones utilizaré Resin, para la documentación del portal algún Wiki gratuito (eso si no me hago yo uno muy sencillo solo para esto) y como base de datos MySql.
Como veis, la parte técnica está bastante clara. Pero lo bueno de hacer un juego son las propias dificultades intrínsecas de la programación de juegos: el motor de turnos, la estrategia, crear las reglas, sistemas de monitorización para evitar abusos y trampas, etc. Mucho curro.
Y tambien hay que buscarle un nombre, que todavia no tiene! Por ahora su nombre clave es "Space Invaders", aunque es solo eso, su nombre clave. Además hay que hacer o buscar gráficos para el juego, hacer un diseño, hacer un portal de entrada con documentación. Cuantas cosas pendientes todavía!
Y, finalmente, buscar un buen Hosting con Java para el juego, claro (que por cierto ya lo tengo).
Como veo que me ha quedado mucho texto, os adjunto una imagen del mapa de la galaxia generada dinámicamente por mi juego. Ya os contaré como la genero.

Bueno, por hoy ya está bien, ya está descubierto el pastel de lo que me trato entre manos. No os perdais los sucesivos posts sobre Space Invaders.
Vaya, parece que tenemos un programador gracioso en el equipo. Mola.
SQWORD GetGlobalTime( const TCHAR* Filename )
{
//return greenwich mean time as expressed in nanoseconds since the
//creation of the universe. time is expressed in meters, so
//divide by the speed of light to obtain seconds. assumes the
//speed of light in a vacuum is constant. the file specified by
//Filename is assumed to be in your reference frame, otherwise you
//must transform the result by the path integral of the minkowski
//metric tensor in order to obtain the correct result.
return Time;
}
Via The Daily WTF