Sunday, July 27, 2008

iPhone Apps for the average gringo

Ahora se me dio por hacer aplicaciones para iPhone. Antes de largarme, y despues de haber bajado todo lo necesario (XCode, iPhone SKD, etc) se me ocurrio pasar por Apple a ver que tipo de aplicaciones se estan desarrollando, no sea cosa que termine haciendo algo que ya esta disponible. Hay mas de 2000 aplicaciones para iPhone, juegos, utilitarios y plugins para redes sociales pero la que no puede faltar es la que la te puede salvar la vida en este mundo controlado por el terrorismo. Si!, si sos un gringo idiota y tenes un iPhone no te podes perder la aplicacion que te puede salvar el culo - "Terrorism Headlines & Current Threat Level" - porque hay que saber cuando te va a caer un avion en la cabeza!!..yeah!!..USA!!..USA!!..


"See what the national terror alert is currently set to as well as recent terrorism-related headlines in this customized iPhone web app"

Friday, March 28, 2008

Internacionalizacion (i18n) con Flex 3

La version 3 de Macromedia Flex viene con un soporte para localizacion mucho mas flexible que la version 2. La opciones que ofrece esta nueva version son:
  1. Poner todos los recursos en modulos, en lugar de la aplicacion. Estos modulos se pueden pre-cargar para un locale en particular cuando se inicia la aplicacion y cargar luego mas locales si hiciera falta.
  2. Se pueden compilar mutiples locales en una sola aplicacion o modulo.
  3. Se accede a los recursos a traves de un nuevo ResourceManager. Se puede cambiar el idioma en tiempo de ejecucion y controlar en que locale se buscan recursos.
  4. Las expresiones que esten asociadas al ResourceManager (binding) se actualizan automaticamente si el locale cambia. Los componentes son notificados para que hagan los ajustes correspondientes.
  5. Es posible localizar images, sonidos y otros recursos, ademas de las cadenas de texto.
  6. Se pueden crear programaticamente recursos en tiempo de ejecucion a partir de archivos xml, queries a la base de datos, etc.
Paso a mostrarles una forma "facil" de hacer una aplicacion flex con i18n y despues les muestro algo que no vi en los manuales de Flex y que seguramente les resultara de utilidad: "Como cambiar el idioma de la aplicacion basado en el idioma del navegador".

Cambiado el idioma en tiempo de ejecucion desde la aplicacion

Los pasos a seguir son los siguientes:
  1. Creen un proyecto Flex...no es dificil
  2. En la raiz del proyecto creen una carpeta "locale"
  3. Dentro de esa carpeta vamos a armar 2 carpetas mas para los locales
  4. Una carpeta para idioma ingles gringo: en_US
  5. Otra carpeta para castellano criollo: es_AR
  6. Dentro de cada una de estas carpetas vamos a poner nuestros archivos de propiedades. Por ejemplo, recursos.properties
  7. En el archivo recursos.properties de la carpeta es_AR ponemos el par key=value siguiente: jota = Juan Bello
  8. En el archivo recursos.properties de la carpeta en_US ponemos el par key=value siguiente: jota = John Beatiful
  9. Actualizamos las opciones del compilador (boton derecho -> propiedades -> Flex compiler...sarasasasasa...) -locale=es_AR,en_US -allow-source-path-overlap=true -source-path=..\locale{locale}
  10. Bien, ahora tenemos que crear recursos localizados para es_AR porque solo estan disponibles out-of-the-box los idiomas en_US y ja (Ja-pones). Abrimos un shell (cmd)
  11. Vamos al directorio bin de la instalacion de Flex y ejecutamos: copylocale en_US es_AR
    10. Fijense en FLEX_HOME\frameworks\locale si aparecio una carpeta es_AR? si? Esto es para la localizacion de recursos de Flex. Si no lo hacen va aparecer un error que dice "No encuentro el recurso Collections para es_AR" y otros similares.
  12. Tolis!
Ahora al codigo fuente para probarlo.
jota = Juan Bello

jota = John Beautiful



Autodetectar el idioma del usuario para localizar una aplicacion Flex 3

Bien, segun el manual hay varias formas de hacer esto:
  1. Poner un combo y pedirle al usuario que elija. Despues guardo la opcion en una cookie o algo asi. Ya lo mostre en el caso anterior pero no es lo que quiero.
  2. Usar la propiedad Capabilities.language de ActionScript esto me da el lenguaje para Adobe® Flash® Player y Adobe AIR™ (no se si me da el idioma DEL USUARIO)
  3. Usar el header Accept-Language. Cuando el browser hace un request vienen los lenguajes posta..en el orden de preferencia. Hay que parsear el header y sacar el primero que es el que esta usando el usario. Es algo asi: en-us,es-ar;q=0.7,ja;q=0.3 (Yo tengo en_US, es_AR y ja...pones)
  4. Utilizar el lenguaje del sistema operativo o del browser usando Javascript.
La primera opcion es una cagada porque yo no quiero que el usuario seleccione nada. La segunda opcion no se si anda, es decir, me devuelve el idioma del player no se si corresponde con el del usuario. La cuarta desde ya les digo que NO ANDA. En mi caso tengo instalado Firefox en ingles y si accedo a Javascript para ver el idioma a traves del objeto navigator no obtengo NADA. Fijense bien pero a mi, navigator.userLanguage da "undefined" tanto para Firefox como para Explorer, lo mismo para con navigator.language. Siempre da el idioma del browser, NO el del usuario. En mi caso siempre devuelve en_US aunque tenga seleccionado es_AR.

La tercera opcion funciona.....pero es un poquito rebuscada. Les paso la receta a medio hacer:
  1. Hacen un servlet que tome el header "Accept-Language" y lo parsee.
  2. Dentro del proyecto Flex, en la carpeta html-template, agarran el archivo index.template.html
  3. Dentro de ese archivo hacen una llamada asicrona el servlet (seh...con AJAX..XMLHTTPRequest) para obtener el idioma
  4. En el mxml usan el ExternalInterface para hacer la llamada a Javascript
  5. Listo el pollo!
Pseudo-codigo a medias para pruebas:

public function callWrapper():void {
if (ExternalInterface.available) {
var wrapperFunction:String = "getLanguage";
idioma = ExternalInterface.call(wrapperFunction);
//Alert.show(idioma);
} else {
// Defecto
idioma = "es_US";
}
resourceManager.localeChain = [idioma];
}


protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String prefLanguage = req.getHeader("Accept-Language");
// Parsing sarasa..sasaa
System.out.println(prefLanguage);
super.doGet(req, resp);
}


function getLanguage() {
return navigator.language; // Esto no anda, sepanlo!..Aca iria XMLHTTPRequest..get..sarassaaaa
}

Sunday, December 16, 2007

"Community Edition" quiere decir que no anda

Probando Liferay 4.3.5

Lo unico que queria era probar unos portlets JSR-168 que habia bajado de por ahi. Descargue Liferay Portal, lo configure para que use MySQL en lugar de HQL. Despues de un par de correcciones y problemas menores con Lucene (si tienen problemas de bloqueos borren los archivos generados y listo) pude hacer andar el puto portal. Bien, ahora era cuestion de crear usuarios, asignarlos a grupos, configurar sus roles, crear un par de paginas y tirar mis portlets.
Resulta que el portlet de administracion, con un usuario en rol administrador, no me deja hacer nada. No puedo crear locations, ni grupos de usuarios ni nada..y lo poco que puedo crear desaparece misteriosamente sin dejar rastro.
Fuck you Liferay...me voy a probar otra cosa. Cuando lo mas basico no funciona no vale la pena perder el tiempo dandole mas vueltas.

Avisen cuando saquen una version estable. Salu2

Tuesday, February 13, 2007

OSCache de OpenSymphony

Por si les paso y no saben que hacer.

Como obtener una unica instancia del GeneralCacheAdministrator (implementando un singleton)

import com.opensymphony.oscache.general.GeneralCacheAdministrator;

public class CacheAdmin {
private static GeneralCacheAdministrator theCacheAdmin = null;
private CacheAdmin(){
//
}
public static GeneralCacheAdministrator getInstance(){
if(theCacheAdmin == null){
theCacheAdmin = new GeneralCacheAdministrator();
}
return theCacheAdmin;
}
}

Despues, al momento de utilizarlo hacen:

GeneralCacheAdministrator admin = CacheAdmin.getInstance();

Monday, January 15, 2007

Portal, portlets y otras yerbas.

Buscando documentacion sobre Websphere Portal me tope con un articulo de IBM un poquito desactualizado. La nota comienza asi: "Ya sabemos que un portlet es un servlet...". En serio? No seria mejor decir "Un portlet ERA un servlet..". Antes de la JSR-168 (Portlet specification) un portlet era un servlet ya que la clase Portlet extendia a la clase Servlet. Desde la JSR-168 esto ya no es cierto, uno Portlet NO ES un Servlet. Si bien los conceptos son similares estaria bueno que los muchachos de IBM dejaran de publicar esas notas, salvo que, claro...las actualicen.

Wednesday, January 03, 2007

Midiendo tiempos...sin Annotations

Que pasa si no dispongo de Java 5.0 y no puedo hacer uso de las annotations? Bien, aca esta la solucion al ejemplo anterior pero sin anotaciones.
package com.miempresa.training.aop.advices;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class MiAOPTimer implements MethodInterceptor {
private static Log logger = LogFactory.getLog(MiAOPTimer.class);

public Object invoke(MethodInvocation methodInvocation) throws Throwable {
long t1 = System.currentTimeMillis();
Object retorno = methodInvocation.proceed();
long t2 = System.currentTimeMillis();
logger.info("Método:"+methodInvocation.getMethod().getName()+" ("+(t2-t1)+" ms)");
return retorno;
}
}

El primer cambio notorio es que ahora nuestro advice debe implementar una interfase y sobrescribir el metodo invoke, el resto del codigo queda igual.
Finalmente, nuestro archivo de configuracion de Spring queda de la siguiente forma:
<beans>
<aop:config>
<aop:advisor pointcut="execution(* com.miempresa.training..*.*(..))"
advice-ref="MiAOPTimer"/>
</aop:config>
<bean id="usuarioService" class=com.miempresa.training.aop.UsuarioServiceImpl"/>
<bean id="MiAOPTimer" class="com.miempresa.training.aop.advices.MiAOPTimer"/>
</beans>

Midiendo tiempos con Spring AOP

No hay nada mas facil que integrar AOP (Aspect Oriented Programming) con Spring. De hecho, Spring fue diseñado no para proveer la mejor solucion en AOP sino una forma sencilla de integrar aspectos en nuestras aplicaciones.
En este ejemplo quiero mostrar como se puede armar una rutina que mida el tiempo consumido por cada metodo sin llenar nuestro codigo de System.currentTimeMillis().

El primer paso es armar nuestro around advice:
package com.miempresa.training.aop.advices;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class MiAOPTimer {
private static Log logger = LogFactory.getLog(MiAOPTimer.class);

@Around("execution(* com.miempresa.training..*.*(..))")
public Object cronometro(ProceedingJoinPoint pjp) throws Throwable{
long t1 = System.currentTimeMillis();
Object retorno = pjp.proceed();
long t2 = System.currentTimeMillis();
logger.info("Método: "+pjp.getSignature().getName()+" (" + (t2-t1) + " ms)");
return retorno;
}
}

Basicamente lo que hace es ejecutar el metodo "cronometro" para cada metodo, de cualquier clase, bajo el paquete com.miempresa.training.El nombre del metodo puede ser cualquiera, solo debemos tener en cuanta que debe tomar un ProceedingJoinPoint como parametro, retornar un objeto e invocar al metodo proceed sobre el parametro.

El archivo de configuracion de Spring debe definir el advice y el tag de autoproxies.
<beans>
<bean id="usuarioService" class="com.miempresa.training.aop.ServicioImpl"/>
<aop:aspectj-autoproxy/>
<bean id="miAOPTimer" class="com.miempresa.training.aop.advices.MiAOPTimer"/>
</beans>

Sunday, July 30, 2006

Spring te da alas!!

Aprovechando un curso de Spring que tengo que preparar voy a subir algunos de los articulos que redacte y el codigo fuente de los ejemplos. Voy a empezar con Remoting, donde voy a mostrar como exportar beans a traves de RMI, los protocolos de Caucho - Hessian y Burlap - y un par de cosas mas.