Cuando se carga una página GeneXus se encarga de colocar el foco en el primer campo editable que encuentra, pero que pasa si queremos poner el foco en determinado campo de la pantalla?
En muchos casos queremos que el foco vaya a un campo particular del form que no necesariamente es el primer campo de la pantalla. Es más, nos puede pasar que queramos que el usuario ingrese datos en un grid apenas se cargue la página, para lo cual desearíamos poner el foco en el primer campo de la primera fila de un grid.
Para cumplir con ese deseo de controlar donde irá el foco luego de cargada la página, y en especial que vaya a un campo de un grid, surge la idea de desarrollar el user control, FocusController.
Como funciona?
Imaginen un ejemplo muy simple de un grid con un par de variables y el siguiente evento load para cargar los valores:
Event Grid1.Load
for &I=1 to 5
&Var1 = &i
&Var2 = &i
grid1.Load()
endfor
EndEvent
Pero la idea es que al cargar el webpanel el foco vaya al campo asociado a &Var1 en la primera fila del grid, entonces lo que hacemos es colocar el user control FocusController en el form y cambiamos el evento load de la siguiente manera:
Event Grid1.Load
for &I=1 to 5
if &I=1
FocusController1.OnLoadControlFocus = &Var1.InternalName
endif
&Var1 = &i
&Var2 = &i
grid1.Load()
endfor
EndEvent
La propiedad OnLoadControlFocus del user control debe ser cargada con el InternalName (nombre interno que se le dará al campo en el html generado) de un campo que pueda recibir el foco, como por ejemplo: var/att editables, imagenes, o botones.
Nota: el user control fue desarrollado y testeado con la versión GeneXus Evolution 1, no se asegura su funcionamiento con versiones anteriores o posteriores de GeneXus.
martes, 27 de abril de 2010
lunes, 19 de abril de 2010
Problemas con Favicon.ico
Hace unos días me contaron que en el log del servidor aparecía el siguiente error:
[error] [client 192.168.51.251] File does not exist: /opt/jboss-ews-1.0_A/httpd/www/html/favicon.ico
El error aparecía en el Apache http server el cual se utiliza como "load balancer" entre los distintos application server, Jboss.
A primera vista es obvio pensar que se esta referenciando al archivo favicon.ico en la ruta mencionada en el error y dicho archivo no se encuentra, lo cual se confirmó luego de mi prueba, pero de todos quise armar un ambiente y efectivamente obtener el mismo error, la única diferencia sería hacerlo en un ambiente Windows y no Linux.
Lo primero que necesitaba era poder contar con varios jboss de forma de poder hacer el balanceo de carga, pero la idea era hacer todo en mi máquina, así que configuré dos IP's virtuales de forma de levantar una instancia de jboss en cada una de ellas.
Para hacer esto agregué un nuevo Network adapter (Add new hardware device - > (manual) Network Adapter - > Microsoft Loopback Adapter) y le configuré dos IP's (que no estuvieran en el rango de mi red). Para hacer eso se debe ir a las propiedades de la conexión recién creada y en las properties de la sección Internet Protocol (TCP/IP) configurar una IP, ej: 192.168.1.140, y luego en Advanced agregar una nueva IP, ej: 192.168.1.141.
Lo siguiente fue instalarme el Apache Http Server, y luego el modulo mod_jk de forma tal que mi Apache http server se pueda encargar del load balancing. El archivo a bajar tendrá un nombre de la forma mod_jk-x.x.xx-httpd-x.x.xx.so, dependiendo de la versión, en mi caso me baje la última disponible en ese momento, 1.2.30. Para instalarlo se debe copiar al directorio APACHE_HOME/modules y renombrarlo a mod_jk.so.
Ya tenía instalado Jboss por lo cual no fue necesario instalarlo.
A partir de este momento tenía todo lo necesario, ahora solo restaba comenzar con las configuraciones..
Configuraciones a hacer en Apache:
1. Editar el httpd.config ubicado en apache-home\conf y agregar:
#mod_jk setup
Include conf/extra/mod_jk.conf
2. Crear el archivo mod_jk.conf en apache-home\conf\extra y agregar lo siguiente:
# Load mod_jk module
# Specify the filename of the mod_jk lib
LoadModule jk_module modules/mod_jk.so
# Where to find workers.properties
JkWorkersFile conf/workers.properties
# Where to put jk logs
JkLogFile logs/mod_jk.log
# Set the jk log level [debug/error/info]
JkLogLevel info
# Select the log format
JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"
# JkOptions indicates to send SSK KEY SIZE
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
# JkRequestLogFormat
JkRequestLogFormat "%w %V %T"
# Mount your applications
JkMount /MYAPP_NAME/* loadbalancer
# You can use external file for mount points.
# It will be checked for updates each 60 seconds.
# The format of the file is: /url=worker
# /examples/*=loadbalancer
JkMountFile conf/uriworkermap.properties
# Add shared memory.
# This directive is present with 1.2.10 and
# later versions of mod_jk, and is needed for
# for load balancing to work properly
JkShmFile logs/jk.shm
# Add jkstatus for managing runtime data
JkMount status
Order deny,allow
Deny from all
Allow from 127.0.0.1
Aquí se debe reemplazar MYAPP_NAME por el nombre de la webapp en la que queremos hacer load balancing.
3. Crear el archivo workers.properties en apache-home\conf\ con el siguiente contenido:
# Define list of workers that will be used
# for mapping requests
worker.list=loadbalancer,status
# Define Node1
# modify the host as your host IP or DNS name.
worker.node1.port=8009
worker.node1.host=192.168.1.140
worker.node1.type=ajp13
worker.node1.lbfactor=1
# Define Node2
# modify the host as your host IP or DNS name.
worker.node2.port=8009
worker.node2.host=192.168.1.141
worker.node2.type=ajp13
worker.node2.lbfactor=1
# Load-balancing behaviour
worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=node1,node2
worker.loadbalancer.sticky_session=1
#worker.list=loadbalancer
# Status worker for managing load balancer
worker.status.type=status
Aquí estamos definiendo los nodos donde estarán nuestros jboss para hacer el load balancing entre ellos, en este caso el node1 estará en la IP 192.168.1.140 y el node2 en la IP 192.168.1.141, que son las IPs que configuré al principio, en caso de haber usado otras se deben colocar esos números de IP aqui.
4. Crear el archivo uriworkermap.properties en apache-home\conf\ con el siguiente contenido:
# Simple worker configuration file# Mount the Servlet context to the ajp13 worker
/MYAPP_NAME=loadbalancer
/MYAPP_NAME/*=loadbalancer
al igual que antes MYAPP_NAME es el nombre de la webapp que queremos "balancear".
Hasta acá todo lo necesario a configurar en el Apache HTTP Server.
Configuraciones a hacer en JBoss:
1. Como dije antes la idea es levantar dos instancias de JBoss en mi máquina, para hacer esto debemos hacer dos copias del dir jboss-home\server\default, llamar a una node1 y a la otra node2, estos nombres se corresponden con los que configuramos en el archivo workers.properties.
2. Editar el archivo jboss-home\server\node1\deploy\jboss-web.deployer\server.xml y setear:
5. Debemos hacer el deploy de nuestra webapp, MYAPP_NAME, en ambas instancias del jboss, node1 y node2.
Por último solo nos resta levantar las dos instancias de JBoss, para hacer esto podemos hacer lo siguiente:
run.bat --host=192.168.1.140 --configuration=node1 -Djboss.messaging.ServerPeerID=1
run.bat --host=192.168.1.141 --configuration=node2 -Djboss.messaging.ServerPeerID=2
con esto tenemos las dos instancias de JBoss corriendo en nuestra máquina, una en la IP 192.168.1.140 y la otra en la IP 192.168.1.141.
Solo nos resta levantar Apache y comenzar a usar la app.
Cuando levantamos Apache podemos llegar a tener un error como este:
(OS 10048)Only one usage of each socket address (protocol/network address/por
is normally permitted. : make_sock: could not bind to address localhost:
no listening sockets available, shutting down
Unable to open logs
Para solucionarlo podemos editar el archivo httpd.conf y setear la IP de nuestra máquina en lugar de localhost:
Listen 192.168.10.21:80
Lo mismo o un error similar puede pasar si tenemos corriendo el IIS en el mismo puerto (80).
Listo, cuando accedamos a http://localhost/MYAPP_NAME estaremos haciendo load balancing, podemos bajar un node y notar como seguirá funcionando nuestra app.
Volviendo al problema original, cuando accedemos a nuestra app el browser buscaba por el favicon.ico en apache-home\htdocs y el mismo no estaba allí, por lo cual copiando favicon.ico a dicho directorio el problema quedó resuelto.
[error] [client 192.168.51.251] File does not exist: /opt/jboss-ews-1.0_A/httpd/www/html/favicon.ico
El error aparecía en el Apache http server el cual se utiliza como "load balancer" entre los distintos application server, Jboss.
A primera vista es obvio pensar que se esta referenciando al archivo favicon.ico en la ruta mencionada en el error y dicho archivo no se encuentra, lo cual se confirmó luego de mi prueba, pero de todos quise armar un ambiente y efectivamente obtener el mismo error, la única diferencia sería hacerlo en un ambiente Windows y no Linux.
Lo primero que necesitaba era poder contar con varios jboss de forma de poder hacer el balanceo de carga, pero la idea era hacer todo en mi máquina, así que configuré dos IP's virtuales de forma de levantar una instancia de jboss en cada una de ellas.
Para hacer esto agregué un nuevo Network adapter (Add new hardware device - > (manual) Network Adapter - > Microsoft Loopback Adapter) y le configuré dos IP's (que no estuvieran en el rango de mi red). Para hacer eso se debe ir a las propiedades de la conexión recién creada y en las properties de la sección Internet Protocol (TCP/IP) configurar una IP, ej: 192.168.1.140, y luego en Advanced agregar una nueva IP, ej: 192.168.1.141.
Lo siguiente fue instalarme el Apache Http Server, y luego el modulo mod_jk de forma tal que mi Apache http server se pueda encargar del load balancing. El archivo a bajar tendrá un nombre de la forma mod_jk-x.x.xx-httpd-x.x.xx.so, dependiendo de la versión, en mi caso me baje la última disponible en ese momento, 1.2.30. Para instalarlo se debe copiar al directorio APACHE_HOME/modules y renombrarlo a mod_jk.so.
Ya tenía instalado Jboss por lo cual no fue necesario instalarlo.
A partir de este momento tenía todo lo necesario, ahora solo restaba comenzar con las configuraciones..
Configuraciones a hacer en Apache:
1. Editar el httpd.config ubicado en apache-home\conf y agregar:
#mod_jk setup
Include conf/extra/mod_jk.conf
2. Crear el archivo mod_jk.conf en apache-home\conf\extra y agregar lo siguiente:
# Load mod_jk module
# Specify the filename of the mod_jk lib
LoadModule jk_module modules/mod_jk.so
# Where to find workers.properties
JkWorkersFile conf/workers.properties
# Where to put jk logs
JkLogFile logs/mod_jk.log
# Set the jk log level [debug/error/info]
JkLogLevel info
# Select the log format
JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"
# JkOptions indicates to send SSK KEY SIZE
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
# JkRequestLogFormat
JkRequestLogFormat "%w %V %T"
# Mount your applications
JkMount /MYAPP_NAME/* loadbalancer
# You can use external file for mount points.
# It will be checked for updates each 60 seconds.
# The format of the file is: /url=worker
# /examples/*=loadbalancer
JkMountFile conf/uriworkermap.properties
# Add shared memory.
# This directive is present with 1.2.10 and
# later versions of mod_jk, and is needed for
# for load balancing to work properly
JkShmFile logs/jk.shm
# Add jkstatus for managing runtime data
JkMount status
Order deny,allow
Deny from all
Allow from 127.0.0.1
Aquí se debe reemplazar MYAPP_NAME por el nombre de la webapp en la que queremos hacer load balancing.
3. Crear el archivo workers.properties en apache-home\conf\ con el siguiente contenido:
# Define list of workers that will be used
# for mapping requests
worker.list=loadbalancer,status
# Define Node1
# modify the host as your host IP or DNS name.
worker.node1.port=8009
worker.node1.host=192.168.1.140
worker.node1.type=ajp13
worker.node1.lbfactor=1
# Define Node2
# modify the host as your host IP or DNS name.
worker.node2.port=8009
worker.node2.host=192.168.1.141
worker.node2.type=ajp13
worker.node2.lbfactor=1
# Load-balancing behaviour
worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=node1,node2
worker.loadbalancer.sticky_session=1
#worker.list=loadbalancer
# Status worker for managing load balancer
worker.status.type=status
Aquí estamos definiendo los nodos donde estarán nuestros jboss para hacer el load balancing entre ellos, en este caso el node1 estará en la IP 192.168.1.140 y el node2 en la IP 192.168.1.141, que son las IPs que configuré al principio, en caso de haber usado otras se deben colocar esos números de IP aqui.
4. Crear el archivo uriworkermap.properties en apache-home\conf\ con el siguiente contenido:
# Simple worker configuration file# Mount the Servlet context to the ajp13 worker
/MYAPP_NAME=loadbalancer
/MYAPP_NAME/*=loadbalancer
al igual que antes MYAPP_NAME es el nombre de la webapp que queremos "balancear".
Hasta acá todo lo necesario a configurar en el Apache HTTP Server.
Configuraciones a hacer en JBoss:
1. Como dije antes la idea es levantar dos instancias de JBoss en mi máquina, para hacer esto debemos hacer dos copias del dir jboss-home\server\default, llamar a una node1 y a la otra node2, estos nombres se corresponden con los que configuramos en el archivo workers.properties.
2. Editar el archivo jboss-home\server\node1\deploy\jboss-web.deployer\server.xml y setear:
< Engine name="jboss.web" defaultHost="localhost" jvmRoute="node1" >
3. Editar el archivo jboss-home\server\node1\deploy\jboss-web.deployer\META-INF\jboss-service.xml y setear:< attribute name="UseJK" > true < /attribute >
4. Repetir el paso 2 y 3 para el node2 5. Debemos hacer el deploy de nuestra webapp, MYAPP_NAME, en ambas instancias del jboss, node1 y node2.
Por último solo nos resta levantar las dos instancias de JBoss, para hacer esto podemos hacer lo siguiente:
run.bat --host=192.168.1.140 --configuration=node1 -Djboss.messaging.ServerPeerID=1
run.bat --host=192.168.1.141 --configuration=node2 -Djboss.messaging.ServerPeerID=2
con esto tenemos las dos instancias de JBoss corriendo en nuestra máquina, una en la IP 192.168.1.140 y la otra en la IP 192.168.1.141.
Solo nos resta levantar Apache y comenzar a usar la app.
Cuando levantamos Apache podemos llegar a tener un error como este:
(OS 10048)Only one usage of each socket address (protocol/network address/por
is normally permitted. : make_sock: could not bind to address localhost:
no listening sockets available, shutting down
Unable to open logs
Para solucionarlo podemos editar el archivo httpd.conf y setear la IP de nuestra máquina en lugar de localhost:
Listen 192.168.10.21:80
Lo mismo o un error similar puede pasar si tenemos corriendo el IIS en el mismo puerto (80).
Listo, cuando accedamos a http://localhost/MYAPP_NAME estaremos haciendo load balancing, podemos bajar un node y notar como seguirá funcionando nuestra app.
Volviendo al problema original, cuando accedemos a nuestra app el browser buscaba por el favicon.ico en apache-home\htdocs y el mismo no estaba allí, por lo cual copiando favicon.ico a dicho directorio el problema quedó resuelto.
viernes, 16 de abril de 2010
Cosas que no se ven habitualmente por mi barrio
Típica imagen de metro luego de las 10 de la noche.
Yorugua sacando ticket de tren con Pilsen en mano
Si vas a reusar las sábanas pone esto en la puerta para que no las cambien
Bar con todas botellas de wisky o sake
Tomate la cerveza y tira el vaso donde se debe
Máquina para elegir que vas a comer y pagar
Cerveza cusqueña
Voluntario que indica a los peatones cuando deben cruzar el seáforo
Típico escritorio de Uruguayo
Agarrate que se mueve todo
WTF
El padrino en el baño
Te leo las manos
Todo bien con dejarla en la calle pero sacale las llaves
Se enojó
Boy scouts
Antes que te corte el pelo paga tú ticket
Haciendo té
Vista del cementerio desde la habitación
Nieve en primavera
jueves, 15 de abril de 2010
Cambiar dinero en Japón
....tarea por demás interesante.
Hace un tiempo hablé de la amabilidad con la que uno es atendido cuando va al banco, eso no ha cambiado y nada tengo para decir al respecto. Ahora, algo tan simple como cambiar plata en Japón, dolares a yenes en mi caso, puede llegar a ser una experiencia religiosa.
Hoy tenía que cambiar dinero porque ya no tenía yenes, por lo cual fui al primer banco que vi caminando por la calle, no voy a decir que banco dado que no aporta (pero era el Mizuho Bank), no tenía el pasaporte conmigo por lo cual no me fue posible cambiar.
Volver a casa a buscar el pasaporte o ir a otro banco e intentarlo? ir a otro banco.
Quiero cambiar dinero le dije a la señora amable que esta para atender a los clientes que entran al banco.
A la pregunta sobre que clase de cambio, le dije Dolares a Yenes.
Me entregó un formulario donde debía poner mi dirección y teléfono en Japón, mi nombre, y cuanto dinero debía cambiar.
Un embole, pero todo bien...
Espero (casi nada) y me llaman.
Me siento, y entrego mi formulario a la funcionaria.
Olvidé poner el signo de dolares, shit!
Me pregunto: que raro? el formulario es especial para dolares a yenes, sino me hubieran dado otro de otro color y con un titulo que diría euros a yenes por ejemplo. Ok.
Siguiente pregunta: en esta dirección vive?
Siguiente respuesta: no, allí trabajo, me acabo de mudar y no se mi nueva dirección.
Cara de asombro por parte de funcionaria.
Espere un momento por favor, tengo un mapa con mi nueva dirección en mi bolsillo, le digo.
Entrego mapa con dirección.
Puedo sacar una copia, dice la funcionaria.
Si, por supuesto, respondo ya un tanto cansado.
Me pregunto nuevamente: por qué tanta vueltas por dios? enseguida recuerdo un cambio de Montevideo, o a una cholita en Bolivia cambiando dolares por bolivianos sentada en una silla en el medio de la frontera con Perú.
Luego de hacer la copia, ingresar algo en la computadora, otra vez se acerca la funcionaria al escritorio.
Debo admitir que en este momento estuve a punto de levantarme e irme, pero no tenía mis dolares conmigo, los tenía la funcionaria haciéndole algún super chequeo para corroborar que no fueran falsos.
Otra vez pienso: en realidad esta bien todo este chequeo de información, esto les permite tener un trace interesante de cada transacción y en caso de algún problema no habría dudas de donde ir a buscar al autor de la irregularidad, en este caso yo. Pero nuevamente me pregunto, solo quiero cambiar unos pocos dolares, por qué es tan complicado? Y otra vez se me viene a la mente la cholita boliviana.
Por fin! llegan los yenes en una bandejita junto con la funcionaria.
Pero...nueva pregunta: como se llama su empresa?
Mmm más preguntas, qué lindo!, eso pensé, pero no usando esas palabras.
No dije nada, solo le mostré mi tarjeta personal donde decía el nombre y a continuación leí el nombre de la empresa.
La dirección de la empresa que puso en el formulario se corresponde con el nombre de su empresa?
Respuesta: Si
Me entrega el dinero, lo cuento, todo esta ok, muchas gracias, chau hasta mañana.
Como decía mas arriba: una experiencia religiosa!
Hace un tiempo hablé de la amabilidad con la que uno es atendido cuando va al banco, eso no ha cambiado y nada tengo para decir al respecto. Ahora, algo tan simple como cambiar plata en Japón, dolares a yenes en mi caso, puede llegar a ser una experiencia religiosa.
Hoy tenía que cambiar dinero porque ya no tenía yenes, por lo cual fui al primer banco que vi caminando por la calle, no voy a decir que banco dado que no aporta (pero era el Mizuho Bank), no tenía el pasaporte conmigo por lo cual no me fue posible cambiar.
Volver a casa a buscar el pasaporte o ir a otro banco e intentarlo? ir a otro banco.
Quiero cambiar dinero le dije a la señora amable que esta para atender a los clientes que entran al banco.
A la pregunta sobre que clase de cambio, le dije Dolares a Yenes.
Me entregó un formulario donde debía poner mi dirección y teléfono en Japón, mi nombre, y cuanto dinero debía cambiar.
Un embole, pero todo bien...
Espero (casi nada) y me llaman.
Me siento, y entrego mi formulario a la funcionaria.
Olvidé poner el signo de dolares, shit!
Me pregunto: que raro? el formulario es especial para dolares a yenes, sino me hubieran dado otro de otro color y con un titulo que diría euros a yenes por ejemplo. Ok.
Siguiente pregunta: en esta dirección vive?
Siguiente respuesta: no, allí trabajo, me acabo de mudar y no se mi nueva dirección.
Cara de asombro por parte de funcionaria.
Espere un momento por favor, tengo un mapa con mi nueva dirección en mi bolsillo, le digo.
Entrego mapa con dirección.
Puedo sacar una copia, dice la funcionaria.
Si, por supuesto, respondo ya un tanto cansado.
Me pregunto nuevamente: por qué tanta vueltas por dios? enseguida recuerdo un cambio de Montevideo, o a una cholita en Bolivia cambiando dolares por bolivianos sentada en una silla en el medio de la frontera con Perú.
Luego de hacer la copia, ingresar algo en la computadora, otra vez se acerca la funcionaria al escritorio.
Debo admitir que en este momento estuve a punto de levantarme e irme, pero no tenía mis dolares conmigo, los tenía la funcionaria haciéndole algún super chequeo para corroborar que no fueran falsos.
Otra vez pienso: en realidad esta bien todo este chequeo de información, esto les permite tener un trace interesante de cada transacción y en caso de algún problema no habría dudas de donde ir a buscar al autor de la irregularidad, en este caso yo. Pero nuevamente me pregunto, solo quiero cambiar unos pocos dolares, por qué es tan complicado? Y otra vez se me viene a la mente la cholita boliviana.
Por fin! llegan los yenes en una bandejita junto con la funcionaria.
Pero...nueva pregunta: como se llama su empresa?
Mmm más preguntas, qué lindo!, eso pensé, pero no usando esas palabras.
No dije nada, solo le mostré mi tarjeta personal donde decía el nombre y a continuación leí el nombre de la empresa.
La dirección de la empresa que puso en el formulario se corresponde con el nombre de su empresa?
Respuesta: Si
Me entrega el dinero, lo cuento, todo esta ok, muchas gracias, chau hasta mañana.
Como decía mas arriba: una experiencia religiosa!
miércoles, 7 de abril de 2010
Where is Uruguay?
Fuí al correo porque tenía que enviar una carta a Uruguay.
Para cobrarme y poner los sellos debían saber donde estaba enviando la carta, en el sobre decía y obviamente yo les dije también: el país a enviar la carta es Uruguay.
Luego de pasar de una computadora a otra, parece que en el sistema de la primera no aparecía Uruguay, se dieron cuenta que el sistema es el mismo, independiente de la computadora y se percataron que ese país llamado Uruguay no aparecía en el sistema o al menos escrito de la forma "Uruguay".
En la oficina trabajaban unas 4 o 5 personas y ninguna sabía de la existencia de tan raro país, luego de preguntas tales como: Rusia? (está cercano a Rusia), Europe? (es un país de Europa?), había que recurrir a la clásica y ya trillada explicación:
1. South America
2. Movimiento de manos, explicando donde esta Asia, Europa, Amercia del Norte (USA) y América del Sur
3. Brazil
4. Argentina
5. Otra vez movimiento de manos, ubicando donde estaba Brasil y Argentina, para luego pasar si a...
6. Uruguay
Obviamente la amabilidad nunca la dejaron de lado y las disculpas por no saber donde estaba no tardaron en llegar. De todos modos me pregunto:
- es tan raro el país donde vivimos?
- Geografía, se enseña en los colegios?
- globos terráqueos existen por Asia?
Por otro lado también es cierto que si Japón y los japoneses son un punto muy pequeño en el mundo, explicado de forma muy clara acá, quizás es razonable pensar que no existamos, no?
Para cobrarme y poner los sellos debían saber donde estaba enviando la carta, en el sobre decía y obviamente yo les dije también: el país a enviar la carta es Uruguay.
Luego de pasar de una computadora a otra, parece que en el sistema de la primera no aparecía Uruguay, se dieron cuenta que el sistema es el mismo, independiente de la computadora y se percataron que ese país llamado Uruguay no aparecía en el sistema o al menos escrito de la forma "Uruguay".
En la oficina trabajaban unas 4 o 5 personas y ninguna sabía de la existencia de tan raro país, luego de preguntas tales como: Rusia? (está cercano a Rusia), Europe? (es un país de Europa?), había que recurrir a la clásica y ya trillada explicación:
1. South America
2. Movimiento de manos, explicando donde esta Asia, Europa, Amercia del Norte (USA) y América del Sur
3. Brazil
4. Argentina
5. Otra vez movimiento de manos, ubicando donde estaba Brasil y Argentina, para luego pasar si a...
6. Uruguay
Obviamente la amabilidad nunca la dejaron de lado y las disculpas por no saber donde estaba no tardaron en llegar. De todos modos me pregunto:
- es tan raro el país donde vivimos?
- Geografía, se enseña en los colegios?
- globos terráqueos existen por Asia?
Por otro lado también es cierto que si Japón y los japoneses son un punto muy pequeño en el mundo, explicado de forma muy clara acá, quizás es razonable pensar que no existamos, no?
Sigamos jugando, ahora Twitter
Hace un tiempo subí al GeneXus Server una KB que usaba una librería de las tantas que existen para interactuar con la API de Twitter, más específicamente la Yedda Twitter C# Library. La idea era jugar un poco con twitter desde GeneXus.
Para usar la librería utilizo un External Object, que encapsula toda la funcionalidad de la dll. En aquel momento solo probé traer mi lista de followers y mostrarla en un webpanel, algo que quedaba así de simple:
&userString = &twitter.GetFollowersAsJSON(&user,&password)
siendo &twitter mi external object y &userString el json con toda la lista de followers, y luego levantaba la info para poder utilizarla mediante un SDT haciendo:
&Users.FromJson(&userString), siendo &Users un sdt con toda la info que necesito asociada a los followers.
Pero ahora quería poder twittear. Cuando fui a utilizar dicho método, UpdateAsJSON, me encuentro con que al ejecutar se presenta un error (en la librería) que me lo impedía, quizás a causa de no estar actualizada la dll.
A diferencia de lo que buscaba cuando estaba jugando con facebook, ahora no quería utilizar una librería javascript y desarrollar un UC para resolver la integración, dado que no necesitaba nada de interfaz simplemente quería twittear, algo tan simple como pasar mi user y pass y actualizar mi status en twitter.
Así que opte por usar otra librería, ahora java, JTwitter. Como casi todas las librerías, esta tenía muchas mas funcionalidades de las que quería, y además tuve un error al importarla directamente en GeneXus, por lo cual opte por hacer un wrapper, solo disponibilizar aquello que necesitaba y crear un external object en base a ese wrapper:
getStatus(): devuelve el status del usuario
setStatus(text): twittea el texto text
getStatusesCount(): devuelve la cantidad de tweets del usuario
getProfileImageUrl(): devuelve la url de la picture del profile del usuario
Con esos cuatro métodos tengo todo lo que necesito para twittear y mostrar la info del usuario en mi webpanel:
Si quieren pueden bajarse la KB: Twitter desde Genexus Server, y seguir jugando.
Luego que tengan armado el ambiente deben copiar jtwitter.jar y twitter.jar (ambos archivos están en la KB) al directorio lib de su webapp, y ambos deben estar en su classpath. En los Files de la KB también esta el proyecto de NetBeans con el que hice el wrapper, twitter.zip, por si quieren seguir haciendo cosas.
Para usar la librería utilizo un External Object, que encapsula toda la funcionalidad de la dll. En aquel momento solo probé traer mi lista de followers y mostrarla en un webpanel, algo que quedaba así de simple:
&userString = &twitter.GetFollowersAsJSON(&user,&password)
siendo &twitter mi external object y &userString el json con toda la lista de followers, y luego levantaba la info para poder utilizarla mediante un SDT haciendo:
&Users.FromJson(&userString), siendo &Users un sdt con toda la info que necesito asociada a los followers.
Pero ahora quería poder twittear. Cuando fui a utilizar dicho método, UpdateAsJSON, me encuentro con que al ejecutar se presenta un error (en la librería) que me lo impedía, quizás a causa de no estar actualizada la dll.
A diferencia de lo que buscaba cuando estaba jugando con facebook, ahora no quería utilizar una librería javascript y desarrollar un UC para resolver la integración, dado que no necesitaba nada de interfaz simplemente quería twittear, algo tan simple como pasar mi user y pass y actualizar mi status en twitter.
Así que opte por usar otra librería, ahora java, JTwitter. Como casi todas las librerías, esta tenía muchas mas funcionalidades de las que quería, y además tuve un error al importarla directamente en GeneXus, por lo cual opte por hacer un wrapper, solo disponibilizar aquello que necesitaba y crear un external object en base a ese wrapper:
getStatus(): devuelve el status del usuario
setStatus(text): twittea el texto text
getStatusesCount(): devuelve la cantidad de tweets del usuario
getProfileImageUrl(): devuelve la url de la picture del profile del usuario
Con esos cuatro métodos tengo todo lo que necesito para twittear y mostrar la info del usuario en mi webpanel:
Si quieren pueden bajarse la KB: Twitter desde Genexus Server, y seguir jugando.
Luego que tengan armado el ambiente deben copiar jtwitter.jar y twitter.jar (ambos archivos están en la KB) al directorio lib de su webapp, y ambos deben estar en su classpath. En los Files de la KB también esta el proyecto de NetBeans con el que hice el wrapper, twitter.zip, por si quieren seguir haciendo cosas.
domingo, 4 de abril de 2010
Jugando con Facebook
El dilema era: crear otro blog para escribir cosas mas técnicas y menos diarias o seguir usando este...como se puede ver abajo el dilema fue resuelto.
Desde hace un tiempo tenía ganas de poder integrar Facebook con GeneXus, de hecho en la charla que dimos con Javier Larrosa en la XVIII GeneXus Meeting del 2008 algo habíamos mostrado. En esa oportunidad lo hicimos a través de los External Objects de GeneXus, utilizamos una librería desarrollada por Microsoft para interactuar con Facebook. La idea no estaba mal y de hecho pudimos comunicarnos muy fácilmente a través de dicha librería.
El problema con esto es que estábamos usando un producto de un tercero pudiéndolo hacerlo directamente a través de la API de Facebook. Esto tenía como inconveniente que siempre que ese tercero cambie nosotros debemos cambiar nuestro External Object para actualizar la lista de métodos/propiedades.
Eso fue justamente lo que nos paso luego del evento, Microsoft cambió varias interfaces de dicha librería debido a cambios en la propia API de Facebook, y lo que nosotros teníamos funcionando y que de hecho mostramos en la demo de la charla dejó de funcionar.
Lo interesante de utilizar un External Object era que teníamos la API de Facebook encapsulada en dicho objeto y era muy fácil su utilización.
Podíamos seguir en la línea de utilizar una librería de un tercero o podíamos nosotros mismos interactuar con la API de Facebook sin necesidad de un tercero, y esa es justamente la línea que elegimos, desarrollar una serie de User Controls que resuelvan la comunicación con Facebook desde nuestros objetos.
En cualquier caso, ya sea utilizando una librería de un tercero o accediendo a la API directamente, tenemos que crear una aplicación en Facebook, para lo cual primero que nada debemos agregar a nuestro perfil de Facebook la application: Developer. Y luego crear una nueva Application, esto nos permitirá obtener una ApiKey con la cual podremos acceder a la API. Acá pueden saber un poco mas al respecto.
La idea de los User Controls es utilizar la JavaScript Client Library, para acceder a la API a través de código javascript. No queremos hostear una app en Facebook, por lo cual cuando creemos nuestra app en Developer solo nos interesará:
Basic - API Key, Key necesaria para poder interactuar con la API
Connect - Connect URL, url donde Facebook enviará una session válida para comunicarnos con ellos
Como pueden ver, también configuré un valor para Base Domain, en este caso localhost. Esto se debe a que tendremos una comunicación entre nuestra app y Facebook a través de js, por lo cual habrá una Cross Domain Communication, por lo cual debemos crear un Channel entre nuestra app y Facebook, para lo cual necesitamos crear un archivo xd_receiver.htm y almacenarlo en nuestro server. Pueden obtener mas detalles aquí, pero a los efectos de la utilización de los User Controles en GeneXus solo tenemos que tener en cuenta dos cosas:
1. cuando creamos la app en Facebook indicar un Base Domain, con lo cual indicamos el nombre del dominio en el cual estará el archivo xd_receiver.htm
2. cuando utilicemos el User Control: FacebookConnect, el cual nos permitirá conectarnos con Facebook, debemos indicar la ruta a dicho archivo a través de la property xdChannelUrl, cuyo valor por defecto es "/xd_receiver.htm".
Por lo cual si en el UC indicamos como xdChannelUrl el valor "/xd_receiver.htm", entonces en el caso de .Net debemos almacenar el archivo en: C:\Inetpub\wwwroot, y en el caso de Java utilizando tomcat como webserver en: C:\Program Files\Apache Software Foundation\Tomcat 6.0\webapps\ROOT.
Los tres User Controls que tenemos al día de hoy son:
FacebookConnect: necesario para establecer la conexión entre nuestra app y Facebook.
Text: text del botón que se agregara a nuestro form y que nos permitirá establecer la comunicación con Facebook, valor por defecto: "Connect with Facebook".
ApiKey: como mencionamos antes es la Key asociada a la app que creamos en Facebook.
xdChannelUrl: url o ruta al archivo xd_receiver.htm que nos permitirá establecer una cross domain communication entre nuestra app y Facebook, valor por defecto: "/xd_receiver.htm"
Size: tamaño del boton, valores posibles: small, medium, large, or xlarge, valor por defecto: "medium".
FacebookLoggedUser: muestra la foto de perfil y el nombre del usuario logeado a Facebook.
Width: width de la foto, valor por defecto: 50
Height: height de la foto, valor por defecto: 50
FacebookLogo: true/false, indica si se quiere mostrar el logo de Facebook o no en la foto, valor por defecto: true.
Linked: true/false, indica si se quiere tener un link al perfil de Facebook en la foto de perfil, valor por defecto: true.
FacebookShare: permite compartir un link en el muro del usuario logeado
Link: link a compartir una vez que el user hace click en el boton asociado
Type: tipo de boton, valores posible
Pueden obtener los controles en la gallery de GeneXus.
Si se fijan el código de estos User Controls es muy simple, por lo cual pueden chequear la docum de la JavaScript Client Library de Facebook y desarrollar el propio en base a sus necesidades.
update
Dado algunos cambios que sufrió la api de Facebook he realizado algunos cambios. Paso a hacer deprecated la JavaScript Client Library y con ello varios métodos y formas de realizar determinadas acciones.
Eliminé los user controls FacebookLoggedUser y FacebookShare dado que el Facebook Markup Language (FBML), lenguage utilizado en dichos controles, paso a ser deprecated (o en vías de serlo). De todos modos quedó todo armado hacer lo que hacían estos controles
Realicé cambios en la implementación del FacebookConnect los cuales son transparentes para quien utiliza el control, pero que eran necesarios para que funcione la autorización y autenticidad con Facebook.
Agregué un nuevo user control, FacebookFriends, que me pareció interesante pensando en el desarrollo de una aplicación que lo utilizara para explotar los datos obtenidos. Como su nombre lo indica el FacebookFriends obtiene la lista de los amigos del usuario logeado, deja cargada una colección con dichos datos.
Para que funcione el FacebookFriends es necesario tener un FacebookConnect de modo de resolver la autorizcion y autenticacion, una vez que el usario se logea a Facebook y permite acceso para que nuestra app
acceda a la lista de sus amigos obtendremos la collection de amigos a través de un sdt.
Cuando se arrastra el user control FacebookFriends se importa el xpz con el sdt que utilizara el uc para cargar la lista de amigos, la información de los amigos que se esta cargando hoy en día (podría agregarse mas data) son: id y nombre.
Para cargar la foto de todos mis amigos en un free style grid podría hacer algo como esto:
Event FacebookFriends1.AfterFriendsLoaded
for &friend in &friends
&imagesDataItem = new()
&imagesDataItem.Id = &friend.id
&imagesDataItem.Thumbnail = "http://graph.facebook.com/" + &friend.id + "/picture"
&imagesDataItem.Image = "http://graph.facebook.com/"+ &friend.id + "/picture?type=large"
&imagesDataItem.Caption = &friend.name
&imagesData.Add(&imagesDataItem)
endfor
&tic = Servernow()
EndEvent
en el evento AfterFriendsLoaded del user control FacebookFriends cargo un sdt con la información de los amigos (id, name y foto).
Event grid1.Load
for &imagesDataItem in &imagesData
image1.FromURL(&imagesDataItem.Image)
grid1.Load()
endfor
EndEvent
y luego en el evento load de la grid cargo las fotos.
Notar que estoy usando otra sdt para cargar los datos de cada amigo cuando en realidad el UC podría ya devolver dicha información, esto es solo a los efectos de mostrar que dado el id de un user en Facebook puedo obtener información de dicho user consultando la Graph API.
Toda la documentación necesaria para interactuar con Facebook vía js esta en la JavaScript SDK.
Estos dos controles los pueden encontrar en el Marketplace de GeneXus.
Desde hace un tiempo tenía ganas de poder integrar Facebook con GeneXus, de hecho en la charla que dimos con Javier Larrosa en la XVIII GeneXus Meeting del 2008 algo habíamos mostrado. En esa oportunidad lo hicimos a través de los External Objects de GeneXus, utilizamos una librería desarrollada por Microsoft para interactuar con Facebook. La idea no estaba mal y de hecho pudimos comunicarnos muy fácilmente a través de dicha librería.
El problema con esto es que estábamos usando un producto de un tercero pudiéndolo hacerlo directamente a través de la API de Facebook. Esto tenía como inconveniente que siempre que ese tercero cambie nosotros debemos cambiar nuestro External Object para actualizar la lista de métodos/propiedades.
Eso fue justamente lo que nos paso luego del evento, Microsoft cambió varias interfaces de dicha librería debido a cambios en la propia API de Facebook, y lo que nosotros teníamos funcionando y que de hecho mostramos en la demo de la charla dejó de funcionar.
Lo interesante de utilizar un External Object era que teníamos la API de Facebook encapsulada en dicho objeto y era muy fácil su utilización.
Podíamos seguir en la línea de utilizar una librería de un tercero o podíamos nosotros mismos interactuar con la API de Facebook sin necesidad de un tercero, y esa es justamente la línea que elegimos, desarrollar una serie de User Controls que resuelvan la comunicación con Facebook desde nuestros objetos.
En cualquier caso, ya sea utilizando una librería de un tercero o accediendo a la API directamente, tenemos que crear una aplicación en Facebook, para lo cual primero que nada debemos agregar a nuestro perfil de Facebook la application: Developer. Y luego crear una nueva Application, esto nos permitirá obtener una ApiKey con la cual podremos acceder a la API. Acá pueden saber un poco mas al respecto.
La idea de los User Controls es utilizar la JavaScript Client Library, para acceder a la API a través de código javascript. No queremos hostear una app en Facebook, por lo cual cuando creemos nuestra app en Developer solo nos interesará:
Basic - API Key, Key necesaria para poder interactuar con la API
Connect - Connect URL, url donde Facebook enviará una session válida para comunicarnos con ellos
Como pueden ver, también configuré un valor para Base Domain, en este caso localhost. Esto se debe a que tendremos una comunicación entre nuestra app y Facebook a través de js, por lo cual habrá una Cross Domain Communication, por lo cual debemos crear un Channel entre nuestra app y Facebook, para lo cual necesitamos crear un archivo xd_receiver.htm y almacenarlo en nuestro server. Pueden obtener mas detalles aquí, pero a los efectos de la utilización de los User Controles en GeneXus solo tenemos que tener en cuenta dos cosas:
1. cuando creamos la app en Facebook indicar un Base Domain, con lo cual indicamos el nombre del dominio en el cual estará el archivo xd_receiver.htm
2. cuando utilicemos el User Control: FacebookConnect, el cual nos permitirá conectarnos con Facebook, debemos indicar la ruta a dicho archivo a través de la property xdChannelUrl, cuyo valor por defecto es "/xd_receiver.htm".
Por lo cual si en el UC indicamos como xdChannelUrl el valor "/xd_receiver.htm", entonces en el caso de .Net debemos almacenar el archivo en: C:\Inetpub\wwwroot, y en el caso de Java utilizando tomcat como webserver en: C:\Program Files\Apache Software Foundation\Tomcat 6.0\webapps\ROOT.
Los tres User Controls que tenemos al día de hoy son:
FacebookConnect: necesario para establecer la conexión entre nuestra app y Facebook.
Text: text del botón que se agregara a nuestro form y que nos permitirá establecer la comunicación con Facebook, valor por defecto: "Connect with Facebook".
ApiKey: como mencionamos antes es la Key asociada a la app que creamos en Facebook.
xdChannelUrl: url o ruta al archivo xd_receiver.htm que nos permitirá establecer una cross domain communication entre nuestra app y Facebook, valor por defecto: "/xd_receiver.htm"
Size: tamaño del boton, valores posibles: small, medium, large, or xlarge, valor por defecto: "medium".
FacebookLoggedUser: muestra la foto de perfil y el nombre del usuario logeado a Facebook.
Width: width de la foto, valor por defecto: 50
Height: height de la foto, valor por defecto: 50
FacebookLogo: true/false, indica si se quiere mostrar el logo de Facebook o no en la foto, valor por defecto: true.
Linked: true/false, indica si se quiere tener un link al perfil de Facebook en la foto de perfil, valor por defecto: true.
FacebookShare: permite compartir un link en el muro del usuario logeado
Link: link a compartir una vez que el user hace click en el boton asociado
Type: tipo de boton, valores posible
s: box_count, button_count, button, icon, or icon_link, valor por defecto: button_countPueden obtener los controles en la gallery de GeneXus.
Si se fijan el código de estos User Controls es muy simple, por lo cual pueden chequear la docum de la JavaScript Client Library de Facebook y desarrollar el propio en base a sus necesidades.
update
Dado algunos cambios que sufrió la api de Facebook he realizado algunos cambios. Paso a hacer deprecated la JavaScript Client Library y con ello varios métodos y formas de realizar determinadas acciones.
Eliminé los user controls FacebookLoggedUser y FacebookShare dado que el Facebook Markup Language (FBML), lenguage utilizado en dichos controles, paso a ser deprecated (o en vías de serlo). De todos modos quedó todo armado hacer lo que hacían estos controles
Realicé cambios en la implementación del FacebookConnect los cuales son transparentes para quien utiliza el control, pero que eran necesarios para que funcione la autorización y autenticidad con Facebook.
Agregué un nuevo user control, FacebookFriends, que me pareció interesante pensando en el desarrollo de una aplicación que lo utilizara para explotar los datos obtenidos. Como su nombre lo indica el FacebookFriends obtiene la lista de los amigos del usuario logeado, deja cargada una colección con dichos datos.
Para que funcione el FacebookFriends es necesario tener un FacebookConnect de modo de resolver la autorizcion y autenticacion, una vez que el usario se logea a Facebook y permite acceso para que nuestra app
acceda a la lista de sus amigos obtendremos la collection de amigos a través de un sdt.
Cuando se arrastra el user control FacebookFriends se importa el xpz con el sdt que utilizara el uc para cargar la lista de amigos, la información de los amigos que se esta cargando hoy en día (podría agregarse mas data) son: id y nombre.
Para cargar la foto de todos mis amigos en un free style grid podría hacer algo como esto:
Event FacebookFriends1.AfterFriendsLoaded
for &friend in &friends
&imagesDataItem = new()
&imagesDataItem.Id = &friend.id
&imagesDataItem.Thumbnail = "http://graph.facebook.com/" + &friend.id + "/picture"
&imagesDataItem.Image = "http://graph.facebook.com/"+ &friend.id + "/picture?type=large"
&imagesDataItem.Caption = &friend.name
&imagesData.Add(&imagesDataItem)
endfor
&tic = Servernow()
EndEvent
en el evento AfterFriendsLoaded del user control FacebookFriends cargo un sdt con la información de los amigos (id, name y foto).
Event grid1.Load
for &imagesDataItem in &imagesData
image1.FromURL(&imagesDataItem.Image)
grid1.Load()
endfor
EndEvent
y luego en el evento load de la grid cargo las fotos.
Notar que estoy usando otra sdt para cargar los datos de cada amigo cuando en realidad el UC podría ya devolver dicha información, esto es solo a los efectos de mostrar que dado el id de un user en Facebook puedo obtener información de dicho user consultando la Graph API.
Toda la documentación necesaria para interactuar con Facebook vía js esta en la JavaScript SDK.
Estos dos controles los pueden encontrar en el Marketplace de GeneXus.
Suscribirse a:
Entradas (Atom)