Referencia dinámica a tipos de clase en Java

Necesitaba aplicar una serie de operaciones en distintos tipos de datos que comparten ciertas características. Hice lo lógico: creé una clase abstracta que implementa las funciones básicas de las características en común e hice que las demás clases fueran subclases de ella.

public abstract class BaseClass {

   // Propiedades y métodos comunes implementados aquí

}
public class SubClass1 extends BaseClass  {

   // Propiedades y métodos exclusivos
}
public class SubClass2 extends BaseClass {

    // Propiedades y métodos exclusivos
}

En los métodos que aplican las operaciones en cuestión declaré como parámetro la super clase (la abstracta) para que pudiera recibir cualquier subclase. El código quedó más o menos así.

public PriorityQueue<BaseClass> operation1 (List<? extends BaseClass> list) {
    // Hacer algo con los elementos en la lista
}

Hasta aquí todo bien.

El problema surgió cuando dentro de una de las operaciones tenía que modificar varias propiedades comunes de los objetos incluidos en la lista. Debido a la forma en la que Java pasa los parámetros (por valor,  aunque los objetos siempre pasan por referencia. Ver aquí), modificar en el método una de las propiedades del objeto no serviría de nada. Lo primero que se me vino a la mente fue crear clones de los objetos de la lista, pero muchos dicen que hay que evitarlos en la medida de lo posible, en especial cuando se tiene una estructura de clases compleja y algunos objetos no implementan la interface Clonable.

Ya he trabajado con clones antes y no hubo mucho problema. Sin embargo, quería ver si podía aplicar la solución de crear copy constructors para cada clase en la estructura y llamarlos dinámicamente. El problema es que necesitaba saber en tiempo real a qué clase pertenecían los objetos en la lista. Cierto: puedo hacer una serie de if con instanceof para probar cada una de las clases, pero se me hacía que había una mejor solución. Un simple:

BaseClass copy = new BaseClass(originalobject)

está fuera de contexto porque la clase base es abstracta (no se puede instanciar directamente).

La solución es relativamente sencilla: después de crear el copy constructor y de llamar en él al copy constructor de la superclase, en las operaciones tomo la clase de los elementos de la lista y creo dinámicamente una instancia de su copy constructor, la cual puedo llamar para crear una nueva instancia de la clase que contendrá los elementos del objeto original más lo que haya necesitado modificar. Al final meto todo en una cola que se ordena solita (basada en el compare de la clase) y es lo que regreso.

Los métodos que se usan:

  • Object.getClass() : para obtener en tiempo real la clase del objeto en cuestión.
  • Class.getDeclaredConstructor(Class) : para obtener el constructor que reciba los parámetros indicados. Como en este caso se trata de copy constructors, el único parámetro es un objeto de la misma clase, determinado con el getClass().
  • Constructor.newInstance(Object): para obtener una nueva instancia de la clase. En este caso, el constructor debe recibir como parámetro un objeto de la clase BaseClass o alguna de sus subclases.

Algo más o menos así:

public abstract class BaseClass {

   protected BaseClass() {
      // Inicialización de propiedades en común
   }

   // Copy Constructor
   protected BaseClass (BaseClass bc) {
       // copiar los datos de bc a esta instancia
   }

}

public class SubClass1 extends BaseClass {

    public SubClass1 {
       super();
       // Inicialización de propiedades exclusivas
    }

    // Copy Constructor
    public SubClass1 (SubClass1 sc1) {
        super(sc1);
        // Copiar los datos exclusivos de sc1 a esta instancia
    }
}

public class SubClass2 extends BaseClass {

    public SubClass2 {
       super();
       // Inicialización de propiedades exclusivas
    }

    // Copy Constructor
    public SubClass2 (SubClass2 sc2) {
        super(sc2);
        // Copiar los datos exclusivos de sc2 a esta instancia
    }
}

Y las operaciones:

public PriorityQueue<BaseClass> operation1 (List<? extends Searchable> list) {

    Class<? extends BaseClass> objclass = null;
    Constructor<? extends BaseClass> theConstructor = null;
    BaseClass newElement = null;

    for (BaseClass bc : list) {
       // Hacer algo con los datos

      objclass = bc.getClass();
      theConstructor = objclass.getDeclaredConstructor(objclass);
      newElement = theConstructor.newInstance(bc);

       // Hacer las operaciones restantes, crear la cola y devolverla
    }
}

Una alternativa más para la referencia dinámica a las clases y sus constructores.

Plugin de Veetle 64 bits

Muy de vez en cuando quiero ver un video o transmisión en vivo que necesita el plugin de veetle, pero el download que viene por default en la página de descargas es para arquitecturas de 32 bits. Intenté instalarlo con ndiswrapper, pero aun así no funcionaba.

Buscando en internet, me encontré que veetle también tiene plugin para arquitecturas de 64 bits, pero no está fácil encontrarlo. Por acá la liga:

http://veetle.com/download.php/veetle-0.9.17plus-linux-install.sh

Instálenlo como usuario normal. Lo que hace es copiar los plugins necesarios al directorio ~/.mozilla/plugins

Listo. VeetleTV funcionando en 64 bits. Rara vez lo uso, pero nunca está de más tenerlo.

Cabe mencionar que vlc también puede reproducir y grabar streams de Veetle. Hay muchos tutoriales en internet, por ejemplo:

http://netimports.blogspot.com/2010/10/how-to-record-watch-veetle-broadcasts.html

Queda para el registro 🙂

Los años maravillosos – Parte 5

A estas alturas creo que no se necesita introducción, ¿verdad? Agarren palomitas, refresco y pónganse muy cómodos, porque creo que ahora sí me extendí.

Si es la primera vez que leen un escrito de esta serie, por acá pueden leer las entregas pasadas:

Ingeniero – Parte 3

Desde octubre de 2001 estuve sin trabajo, buscando a ver en dónde podría conseguir algo. Justo a principios de año (2002), Omar me dijo que la empresa donde laboraba estaba buscando contratar gente. Omar me recomendó, me hicieron entrevista y, de forma por demás rápida, ya tenía trabajo.

La empresa ya tenía planeado en qué proyecto iba a participar, pero para ello necesitaba estudiar una tecnología llamada COM, la cual utilizaría en el trabajo que se me iba a asignar… o al menos ésa era la idea.

Entré a trabajar en un proyecto dentro de Hewlett-Packard Guadalajara, pero los administradores de proyecto estaban en Boise, Idaho, por lo que la comunicación sería totalmente en inglés. Además, mi lugar de trabajo serían las oficinas de HP. Me tenía que levantar más temprano, haría más tiempo en los camiones, pero no importaba; el trabajo era bueno, se veía interesante y parecía que podría crecer profesionalmente.

Algo curioso de este trabajo fue que, por primera vez desde que egresamos de la universidad, Omar y yo estábamos en el mismo lugar (mismas oficinas), pero trabajando en proyectos diferentes.

No pasaron más de 2 meses desde que entré cuando me enviaron a Idaho, a la planta de HP, para entrenamiento. Estuve por allá 3 semanas, viviendo en medio de nieve, frío… Big Brother y un trabajo que no tenía nada que ver con lo que me habían dicho que haría.

Enfado

Creo que no es apropiado contar punto por punto lo que viví en Idaho en lo que respecta a la vida fuera del trabajo. Lo que sí es preciso mencionar es que la empresa quería ahorrarse dinero a toda costa y no le importaba sacrificar la comodidad de sus empleados con tal de que no se gastara tanto.

El trabajo no era nada de lo que me habían dicho que era. Lo que había estudiado solamente sirvió para entender lo que internamente se usaba, pero nunca me tocó jugar con eso. En vez de programar, seríamos prácticamente testers (personas que se dedican a hacer pruebas de algo que ya está terminado, y en muy remotoso casos se le puede meter mano al código). Yo me quejé con mi jefa de México creo que al segundo o tercer día de estar allá, pero la respuesta que recibí fue que conforme el proyecto avanzara iba a tener oportunidad de programar, cosa que era totalmente diferente a lo que habían mencionado al principio.

Las 3 semanas pasaron. Aprendimos lo que había que aprender y regresamos a Guadalajara. Mi jefe inmediato (un ingeniero en electrónica) sugirió que nos dividiéramos el trabajo, ya que eran 4 proyectos y lo conveniente sería que cada uno estuviera a cargo de 2. Yo le di prioridad a él y lo dejé que escogiera, y me quedé con los 2 proyectos restantes. Mi jefe en Idaho resultó ser una persona muy inteligente, muy sociable, muy amable y muy comprensivo; mi trabajo se convirtió en algo realmente sencillo, pues los 2 proyectos que tenía asignados para estar probando rara vez daban problemas. Y no exagero: había días en que llegaba y en 3 horas terminaba el trabajo, por lo que me desocupaba temprano y me quedaba mucho tiempo libre. Pero no puedo mencionar lo mismo sobre mi jefe inmediato: tenía muchos problemas con un proyecto, y no le daba tiempo de atender otro, por lo que me lo asignó voluntariamente a fuerzas. Quedamos 3-1, y no precisamente en un marcador en el que me hubiera gustado ganar. Pero incluso así, yo sacaba el trabajo de las pruebas de 3 proyectos sin muchos problemas mientras él le sufría con el otro (que él mismo escogió).

Lo anterior puede sonar divertido, pero realmente no lo era. Quizá lo que más disfrutaba del trabajo era la cotorreada con los compañeros. Nos poníamos a jugar Magic a la hora de la comida, platicábamos, criticábamos, sufríamos los estragos de la empresa. El ambiente era genial, y conocí gente muy talentosa, entre ella a un chavo que es (y desde entonces lo era) una eminencia en programación en Windows, al grado que fue contratado por Microsoft y terminó yéndose a residir a Redmond, y hasta la fecha aún está por allá.

Me tocó regresar a Idaho varios meses después, en verano (la primera vez fui en invierno y conocí lo que era el frío verdadero). Boise, la capital, es un lugar muy bonito y muy campirano. De hecho, broméabamos diciendo que la mitad de la gente que vive en Boise trabaja para HP y la otra mitad trabaja para la gente que trabaja para HP. Eso sí: las baked potatoes son deliciosas. Pero desde antes de volver a Idaho, yo me quejaba y buscaba la forma de salirme de ese proyecto y que me asignaran otro. El ambiente de trabajo era bueno y la paga no era mala, por lo que nunca me pasó por la mente renunciar. Lo único que me haría salirme de ese trabajo sería que me dieran la beca a Japón, en cuyo caso renunciaría no por gusto, sino porque la ida a Japón era mucho más importante… y de hecho casi sucedió así, y los detalles de mi renuncia los pueden leer por acá. Por cierto, ahora que vuelvo a leer eso que escribí hace 6 años y comparándolo con mi estado actual, he comprendido mucho más el móvil de las empresas respecto al trato a sus empleados.

He de recalcar que no odié (ni odio) a nadie de esa compañía. Mi jefe inmediato le echaba ganas, y mi jefa pues… actuaba porque así tenía que actuar. Por ahí me habían dicho que la empresa había quebrado, pero echándole un vistazo a internet parece que todavía anda por ahí, lo cual me da mucho gusto. Ojalá que sigan echándole ganas, y que en todos estos años haya mejorado el trato y la relación con los empleados.

Semana santa y semana dorada

Para muchos, estas 2 semanas (santa y pascua) significan vacaciones. Si bien no es lo mismo que cuando uno es estudiante y tiene las 2 semanas completas de descanso, al menos un buen número de compañías dan libres desde el jueves. Dejando al lado la violencia que azota al país y el hecho de que este año muchas personas han preferido quedarse en casa, no tener que preocuparse por el trabajo es ya una ventaja (mínima o no es harina de otro costal).

Para mí y mi familia, la semana santa siempre significó abstinencia; mi padre siempre estuvo en contra de que saliéramos, nos divirtiéramos e incluso de que prendiéramos la televisión o el radio, en especial el viernes santo. La visita a los 7 templos el jueves santo era quizá de las únicas actividades familiares que estaban “decididas” cada año, y hasta cierto punto lo disfrutábamos porque, siendo niños, significaba que regresaríamos con una buena dotación de pan, empanadas, y si nos iba bien, una cena, obviamente sin comer carne porque también guardábamos la tradición de no comer carne los viernes durante la cuaresma, ni el jueves ni viernes santo.

No me malentiendan: nací y crecí como católico, y de cierta manera trataba de entender que aunque teníamos vacaciones había que guardar luto por nuestras creencias. No obstante, las interrogantes de “¿por qué nosotros sí y los demás no?” y “¿por qué la gente sale de vacaciones cuando hay que guardar luto?” siempre pasaban por mi cabeza. Lo malo es que bajo la tutela de mi padre, nadie tenía voz ni voto, ni siquiera para preguntar algo así.

Creo que la primera vez que salí de vacaciones en semana santa fue en 1992; justo aquel día de las explosiones en Guadalajara yo estaba en Punta Pérula, Jalisco, gracias a un tío que me invitó. Nada más que no recuerdo si realmente era semana santa o no 悲しい Pero de la que sí estoy seguro fue de una ida a Manzanillo con el grupo de amigos con los que jugaba rol; para entonces ya trabajaba y pude pagarme el viaje. Me la pasé muy bien, cierto, pero el sentimiento de abstinencia siempre estuvo presente…

Todo lo anterior cambió cuando llegué a Japón.

Continue reading “Semana santa y semana dorada”

Stemming

Al momento de extraer las palabras para trabajar con ellas (como con TF-IDF), y después de quitar las que no nos sirven, ya podemos comenzar a trabajar en la creación de un índice. Sin embargo, podemos todavía aplicar una tarea más a esas palabras con objeto de reducir su número, y al mismo tiempo, de “juntar” las que tienen la misma raíz.

De eso se trata el stemming: tomamos una palabra y obtenemos su stem, que en español sería el equivalente al lexema de la palabra; es decir: la parte de ella que no cambia y contiene el significado esencial. Por ejemplo, si tenemos las palabras “niño”, “niña”, “niños”, “niñas”, el lexema de todas ellas es “niñ”. Entonces, al momento de filtrar las palabras y luego contarlas, en vez de tener algo como:

niño    6

niña   13

niños 16

niñas 4

… es recomendable hacer stemming y obtener el lexema de las palabras. Nos quedaría así:

niñ 39

“Agrupamos” muchos conceptos en uno solo. Ya en una aplicación como un motor de búsqueda, al momento de que el usuario busca algo, aplicamos stemming también en la búsqueda. Así. algo como:

“¿Cuántos niños hay en Guadalajara?”

se traduciría en:

niñ guadalajar

(después de quitar las stopwords, los signos y hacer stemming) que es lo que a final de cuentas usaría un motor de búsqueda tradicional.

No necesariamente todos los motores de búsqueda hacen stemming; todo depende de cuál sea la finalidad del mismo. Por ejemplo, uno que tome en cuenta las conjugaciones de los verbos usaría las palabras completas en vez de sintetizarlas usado lexemas (lo cual tendría sentido para el objetivo que persigue). No obstante, en los motores de búsqueda tradicionales (que trabajan con modelos matemáticos) el stemming es un paso cotidiano que se realiza previo a la creación de un índice (que ya detallaré en otro post).

Trials – 100%

Todavía me falta mucho para decir que tengo buen nivel en Super Street Fighter 4, pero por lo menos ya terminé esta parte:

Los que me costaron más trabajo:

  • Level 24 de El Fuerte
  • Level 22 de C. Viper
  • Level 24 de Ibuki (fue la primera que completé… fue frustrante hasta que entendí el Super Jump Cancel)
  • Level 24 de Adon (el link de c. wk, c. mp nomás no me salía)
  • Level 24 de Zangief (ligar esas 4 c. wk fue un triunfo)
Curiosamente, el level 24 de Makoto no me tomó tanto tiempo. Fué nada más acostumbrarme al Hayate Cancel. También el último de Juri no se me hizo tan complicado.
Por supuesto que mi favorito sigue siendo Tekken, pero crecí con Street Fighter 🙂 Ahí la lleva mi Ibuki, pero me falta mucha práctica todavía.

XMMS2 en XMonad

En el post donde hablé de XMonad no puse el script que uso para mostrar información de XMMS2 con dzen en XMonad. Aquí lo agrego:

/usr/local/bin/dzen-xmms2

#!/bin/bash

ICONS=/home/mmedina/Images/Icons/xbm8x8
FONT=-sazanami-*-*-*-*-*-11-10-0-0-p-*-*-*

while true; do
     check=`xmms2 current | tr -d "\n" | wc -m`
     if [ $check == 0 ]; then
     	 echo "^i(${ICONS}/note.xbm) No songs being played"
     else
          current=`xmms2 current`
          totalsongs=`xmms2 list | grep / | wc -l`
    	  cursongstr=`xmms2 list | grep "\->" | cut -d"/" -f1 | tr -d "\->["`
	  cursongnum=`gcalctool -s "${cursongstr} + 1"`
          echo "^i(${ICONS}/note.xbm) ($cursongnum/$totalsongs) $current"
     fi
     sleep 3

done | dzen2 -x 1350 -y 0 -w 350 -h 11 -ta r -fg white -fn $FONT

Dando como resultado:

En el xmonad.hs tengo ligadas las funciones principales de XMMS2 a una combinación de teclas que me permiten controlar la reproducción de audio sin tener que abrir algún programa o escribir comandos en una terminal. Nota: éste no es el xmonad.hs completo:

  dzproc <- spawnPipe myStatusBar
  dateproc <- spawnPipe myDateBar
  xmms2proc <- spawnPipe myMusicBar

  xmonad $ defaultConfig {
  	 terminal = "urxvt -fg white -bg black -tr -sh 10 -fn 'xft:Dejavu Sans Mono:pixelsize=10' +sb"
	 , modMask = mod4Mask
         , startupHook = setWMName "LG3D"
	 , manageHook = manageDocks <+> myManageHook <+> manageHook defaultConfig
         , layoutHook = myLayout
         , logHook = dynamicLogWithPP $ myDzenPP dzproc
             , workspaces = ["term","web","ide","emacs","mail","ooffice","acroread","VB","misc"]
         } `additionalKeys`
	 [ ((controlMask, xK_Print), spawn "sleep 0.2; scrot -s")
	 , ((0, xK_Print), spawn "scrot")
	 , ((mod1Mask, xK_Shift_L), spawn "chkblayout")
	 , ((mod4Mask .|. shiftMask, xK_w), spawn "setwallpaper")
         , ((mod4Mask .|. shiftMask, xK_q), spawn "gnome-session-save --gui --kill")
         , ((mod4Mask .|. shiftMask, xK_l), spawn "gnome-screensaver-command -l")
         , ((mod4Mask .|. shiftMask, xK_z), spawn "xmms2 prev")
         , ((mod4Mask .|. shiftMask, xK_x), spawn "xmms2 pause")
         , ((mod4Mask .|. shiftMask, xK_c), spawn "xmms2 play")
         , ((mod4Mask .|. shiftMask, xK_v), spawn "xmms2 next")
         , ((mod4Mask .|. shiftMask, xK_b), spawn "xmms2 stop")
         , ((mod4Mask, xK_Up), spawn "amixer set Master 3%+")
         , ((mod4Mask, xK_Down), spawn "amixer set Master 3%-")
	 ]

myBgcolor = "#000000"
myStatusBar = "/usr/bin/dzen2 -x 0 -y 0 -h 11 -w 800 -ta l -fn -sazanami-*-*-*-*-*-11-10-0-0-p-*-*-*"
myDateBar = "/usr/local/bin/miscbarinfo"
myMusicBar = "/usr/local/bin/dzen-xmms2"

Estoy buscando una forma de revisar si el daemon de XMMS2 está siendo ejecutado o no. La idea es que si no lo está, ni me canso en parsear la salida de xmms2 current.

Callbacks en Java

Hace días necesitaba implementar algo en Java que me permitiera emular callbacks. Habiendo usado tanto tiempo Java fue curioso que de primera instancia no se me ocurriera usar interfaces. Un googlazo me enseñó la luz, y de ahí en delante fue nada más crear las clases necesarias.

El escenario es el siguiente: hay una clase que hace las veces de fábrica para crear instancias de otra, pero la forma de extraer la información es diferente dependiendo del documento en cuestión. Cada documento está clasificado en grupos, por lo que sé qué reglas tengo que usar para extraer lo de cada grupo. Ciertamente podría hacer todo con un parámetro y revisar el valor con un if para saber qué rutina ejecutar, pero si existen los callbacks, qué mejor (aunque Java no usa apuntadores).

Lo primero es crear la interface que las clases se van a cargar de implementar. Algo como:

public interface OmniAnalyzer {
    public void analyzeDocument(String document);
}

Después, hay que crear una clase por cada grupo de documentos a analizar, y hacer que cada una implemente la interface arriba mostrada:

public class GroupAAnalyzer implements OmniAnalyzer {
    @Override
    public void analyzeDocument(String document) {
       // Analizar documento de acuerdo a reglas de grupo A
    }
}
public class GroupBAnalyzer implements OmniAnalyzer {
   @Override
   public void analyzeDocument(String document) {
       // Analizar documento de acuerdo a reglas de grupo B
   }
}

Y al momento de analizar un documento, en vez de declarar que usamos una instancia de alguna de las clases anteriores, referenciamos directamente la interface que implementan. Así, independientemente de la clase (y las reglas) que se utilice, simplemente hay que llamar a las funciones que sabemos que están implementadas.

public class General {

  private static void analyzeDocument(OmniAnalyzer analyzer, String document) {
    analyzer.analyzeDocument(document);
  }

  public static void main(String a[]) {
    String doc = a[0];
    int group = Integer.parseInt(a[1]);
    OmniAnalyzer analyzer = null;

    if (group == 0)
     analyzer = new GroupAAnalyzer();
    else if (group == 1)
     analyzer = new GroupBAnalyzer();
    else {
       System.err.println("Only accepting groups 0 or 1");
       System.exit(1);
    }

    analyzeDocument(analyzer, doc);
  }
}

Con esto se deja la puerta abierta para agregar nuevos grupos en caso de ser necesario, y sin necesidad de darle en la torre a lo que ya está hecho.

Japón y las tarjetas de puntos

Aunque sé que no son exclusivas de Japón, las tarjetas de puntos abundan por acá, y en todos los colores y sabores que se puedan imaginar.

Nunca está de más una explicación: vas a un negocio (de prácticamente lo que te imagines), haces una compra o pagas por un servicio y te ofrecen tu totalmente nueva e impecable tarjeta de puntos, con la que cuanto más compres (y más puntos acumules, valga la redundancia), más te acercas al descuento o servicio especial que se otorga por llenarla. Casi siempre ese servicio es una cierta cantidad que puedes gastar en la misma tienda, aunque a veces es también un descuento o hasta un servicio gratuito. Todo depende de la tienda, sus productos y promociones.

Continue reading “Japón y las tarjetas de puntos”

Nuevo año fiscal

En Japón, el año fiscal comienza en abril. Es la época donde todo inicia: nuevo año escolar, los recién egresados acuden ya a trabajar (los que consiguieron trabajo), y claro, florecen los cerezos.

La situación con la planta nuclear de Fukushima todavía está lejos de ser controlada, y sigue siendo muy seria. Incluso por acá en Kyushu se ha visto falta de agua embotellada hasta en los súpermercados más pequeños de este pueblo; y no es que aquí no se pueda beber el agua del grifo, sino que la gente compra para enviarla a sus familiares que residen en el área de la capital. Los niveles radiactivos en las cercanías de la planta siguen siendo variables… en fin, esto tardará en normalizarse.

Y es precisamente en este momento cuando los cerezos florecen, proveyendo de esperanza a toda una nación. Cierto: su belleza es efímera (no duran ni 2 semanas así), pero indican el comienzo de algo, y esta vez no pudo llegar en mejor momento.

Continue reading “Nuevo año fiscal”