Tome todas las precauciones con TweetMe4i y JSON

Buscar y registrar mensajes Twitter mediante fuentes abiertas Java y RPG

El mundo de las auditorías es una realidad con la cual las empresas financieras cada vez más aprenden a convivir. Uno de los objetos de las auditorías son los textos enviados a sitios web de medios sociales como Facebook, LinkedIn y Twitter. Este tutorial lo guiará a través de cómo realizar búsquedas en Twitter utilizando RPG en IBM i y registrar los resultados en una tabla DB2.

Aaron Bartell, Software Developer, Krengel Tech

Aaron Bartell PhotoAaron Bartell es desarrollador senior de software en Krengel Technology Inc. Concentra gran parte de sus desarrollos en la creación de aplicaciones modernas utilizando RPG y Java™ en las plataformas Android e IBM i. Es el desarrollador principal de RPG-XML Suite y el principal "impulsor" de OpenRPGUI.com. Le gusta participar en la sólida comunidad de IBM System i a través del Foro, publicación de artículos y ofreciendo software de fuente abierta en su sitio web MowYourLawn.com. Recientemente se ha dedicado a encontrar maneras de utilizar sus habilidades en beneficio de los necesitados. Puso en marcha el sitio web SofwareSavesLives.com como mecanismo para recaudar fondos destinados a la excavación de pozos de agua potable en África y también para la alimentación de los niños que mueren de hambre. Aaron Bartell vive con su esposa y cinco hijos en el sur de Minnesota (EE.UU.) y le gusta tocar guitarra eléctrica y bajo en su banda, Scattered Showers.



25-06-2012

Cuando tiene sentido

Soy muy partidario de mantener todo en RPG al tratar con programación en IBM i. Pienso en la menor cantidad de lenguajes y tiempos de ejecución que tengo que lidiar y en la mayor atención que puedo dedicar a satisfacer las necesidades de negocio en vez de concentrarme en corregir la tecnología. No me interpreten mal, ME GUSTA aprender cosas nuevas fuera del ámbito de RPG – últimamente he estado inmerso en PhoneGap y Apache Callback – pero he aprendido que la adopción de tecnología debe hacerse con una comprensión completa de las consecuencias a largo plazo (por ejemplo, la vida media de la información se duplica y un departamento de TI necesita realizar un seguimiento). Estoy divagando en este preámbulo porque en este artículo voy a mostrar cómo consultar Twitter desde RPG con Java en el medio. La razón por la que sigo este camino (RPG vs directo a Twitter) es que hay bastantes cosas que le faltan a RPG que harían lo anterior mucho más factible, específicamente, una implementación en RPG del mecanismo OAuth de autenticación en Twitter. OAuth es un nuevo mecanismo para autenticación desde un sitio o servicio web en otro. Aprenda más sobre el protocolo de autenticación OAuth desde la Twitter's perspective.


Twitter4j lo hace posible

Uno de los motivos para usar Java es que por su predominancia resulta muy atrayente para los actuales ecosistemas de software - existen MUCHOS proyectos de fuente abierta Java por ahí que son bastante sólidos y de utilización gratis. Para los propósitos de este artículo, se usa el proyecto Twitter4j , gratuito y de fuente abierta. Debe notarse que hay otras Java libraries para Twitter. Elegí Twitter4j porque parece ser la biblioteca más favorable (parecía activa, bien pensada, con una amplia gama de APIs e incluso recursos para depuración, además de una licencia Apache 2.0 que funciona bien en situaciones comerciales). Si no sabe por qué debe preocuparse sobre cuál licencia se utiliza en un proyecto de fuente abierta, entonces usted debe dedicar algunos minutos para informarse sobre la concesión de licensing. He aprendido que no todos los proyectos de fuente abierta son creados iguales y que, definitivamente, escoger proyectos buenos y "seguros" es un arte. Es algo que la mayoría de los programadores debe conocer ya que los litigios aumentan la preocupación sobre algunas licencias (por ejemplo, GPLv3).

Twitter4j tiene muchos recursos que le permiten conectarse con Twitter en varios frentes, pero el objetivo de este artículo es concentrarse exclusivamente en hacer búsquedas en Twitter. Específicamente, vamos a zambullirnos en las capacidades de Búsqueda Avanzada en esta página Twitter para que podamos aprender qué perfil "aaronbartell" está "twitteando" en un plazo determinado.

En este punto, es bueno retroceder hasta unos pocos meses atrás, cuando hice el release de un nuevo proyecto de fuente abierta denominado TweetMe4i. El código inicial básico para TweetMe4i se centró en el envío de actualizaciones de estado a una cuenta Twitter. En la página web TweetMe4i usted puede encontrar documentación sobre cómo registrarse para los diferentes aspectos de Twitter y, también, sobre cómo configurar su IBM i. Este artículo se añade a ese código inicial básico, específicamente TweetMe4i.java, al proporcionar la funcionalidad de búsqueda, como se muestra en el Listado 1, con el método search() de Java. Usted puede encontrar la fuente completa para TweetMe4i.java en el archivo provisto en este artículo.

Listado 1. Código de Búsqueda de Java
public static String search(String searchStr) {
  String result = "";
  StringBuilder jsonTweet = new StringBuilder();
  try {
    System.setOut(new PrintStream(new FileOutputStream("TweetMe4iLog.txt")));

    Twitter twitter = new TwitterFactory().getInstance();
    QueryResult qryResult = twitter.search(new Query(searchStr));

    boolean firstTime = true;
    jsonTweet.append("{ \"tweets\": [");
    for (Tweet tweet : qryResult.getTweets()) {
      if(!firstTime)
        jsonTweet.append(",");
      else;
        firstTime = false;
    jsonTweet.append(DataObjectFactory.getRawJSON(tweet));
    }
    jsonTweet.append("] }");
    result = resultDS("SUCCESS", jsonTweet.toString());
  } catch (Exception te) {
    result = resultDS("FAIL", "Java Exception:" + stackTraceToString(te));
  }
  return result;
}

Como usted puede ver, el método search() de Java recibe y retorna un objeto de cadena de caracteres. Un ejemplo de una cadena de caracteres de búsqueda es el siguiente:

"from:aaronbartell since:2011-11-01 until:2001-11-30"

El concepto básico del método search() de Java es llamar a Twitter con la cadena de caracteres de búsqueda y luego retornar el resultado de esa búsqueda como una cadena de caracteres JSON al programa que llama. En este caso, el programa que llama está escrito en RPG, que revisaremos en una próxima sección. JSON se utiliza como el mecanismo establecido para el retorno de resultados porque es más fácil de procesar en el extremo de RPG, especialmente cuando disponemos de acceso gratis a un analizador JSON de fuente abierta y a un serializador en RPG. Información adicional sobre este tema se presentará más adelante.

En el método search() , usted observará el código que hace una llamada a System.setOut(). Esta llamada se hace de modo que el programa puede redirigir los mensajes de System.out a un archivo de secuencia para hacer mis esfuerzos de correcciones mucho más fáciles. Observe que el código no especifica una ruta de acceso totalmente calificada con TweetMe4iLog.txt. Esto significa que el archivo de secuencia se escribirá en el directorio actual. Usted puede ver directamente su directorio actual por la sencilla introducción de WRKLNK en la línea de comandos de IBM i, sin otras opciones.

A continuación, en el Listado 1 el código obtiene una nueva instancia de un objeto Twitter utilizando la llamada de TwitterFactory.getInstance() . Entonces, el código invoca a twitter.search() y pasa la cadena de caracteres de búsqueda provista en la llamada a este método. En segundo plano se elabora una solicitud HTTP a Twitter.com para presentar la solicitud de búsqueda y recuperar los resultados retornándolos al objeto qryResult . A continuación el programa itera sobre el objeto qryResult y empieza a componer la cadena de caracteres JSON que se retornará al programa RPG. La razón porque la lógica de la composición introduce directamente algunas de las cadenas de caracteres JSON es porque una estructura envolvente es necesaria para el valor de JSON proporcionado por la llamada a DataObjectFactory.getRawJSON(tweet) utilizada para obtener la representación JSON del conjunto de resultados de twitter. Una muestra de la salida JSON resultante se muestra en el Listado 2.

Para hacer que DataObjectFactory.getRawJSON(tweet) funcione correctamente, es necesario añadir una entrada al archivo twitter4j.properties existente, que si usted ha instalado TweetMe4i desde http://mowyourlawn.com/tweetme4i.html estará ubicada en /java/tweetme4i/twitter4j.properties. La adición al archivo twitter4j.properties es jsonStoreEnabled=true.

Listado 2. Resultado JSON del método search()
{
   "tweets":[
      {
         "text":"Opps, wrong url on that last one ( though a great Christmas
            song :-)  Try this one: http://t.co/p1w3x4jt",
         "from_user_id":44956334,
         "id":144505404985057280,
         "from_user":"aaronbartell",
         "created_at":"Wed, 07 Dec 2011 19:55:47 +0000",
         "metadata":{
            "result_type":"recent"
         }
      },
      {
         "text":"Give feedback for next #RPGNextGen 2.0 features
            http://t.co/rwZL1KH2  #opensource #free #RPG #IBMi editor
            #eclipse based",
         "from_user_id":44956334,
         "id":144504285328195584,
         "from_user":"aaronbartell",
         "created_at":"Wed, 07 Dec 2011 19:51:21 +0000",
         "metadata":{
            "result_type":"recent"
         }
      },
      {
         "text":"RT @SystemiNetwork: Maxed Out: New IBM Tools Uses POWER
            to Crush Commodity Server Architectures: .http://bit.ly/u36umU
           #IBMi",
         "from_user_id":44956334,
         "from_user_name":"Aaron Bartell",
         "id":143789937253294080,
         "from_user_id_str":"44956334",
         "from_user":"aaronbartell",
         "created_at":"Mon, 05 Dec 2011 20:32:47 +0000",
         "metadata":{
            "result_type":"recent"
         }
      }
   ]
}

Si este es su primer contacto con JSON, entonces usted puede aprender más aquí. JSON es la sigla de Javascript Object Notation y se hizo popular en el mundo de la programación de navegadores web como una manera fácil de serializar y deserializar objetos de Javascript de modo que puedan comunicarse hacia y desde el servidor. Por ejemplo, en el pasado lo he utilizado mucho con OpenRPGUI y ExtJS. Ultimamente, he extendido el uso de JSON más allá de los escenarios de Javascript. Por ejemplo, JSON ha sido utilizado para comunicarse con una aplicación Android e mis proyectos DynaDroid4i donde Javascript no estaba involucrado en absoluto. No obstante, aún se utilizó JSON para enviar mensajes hacia y desde IBM i al dispositivo móvil Android.


Aspecto del RPG

Ahora es el momento de ir al lado RPG de la solución para ver cómo invocar el método search() de Java. El Listado 3 muestra las líneas principales del programa TM4ISEARCH de RPG. Nota: la fuente completa para TM4ISEARCH puede encontrarse en el archivo zip adjunto a este artículo.

Listado 3. Líneas principales de TM4ISEARCH
       monitor;
         cmd = 'ADDENVVAR ENVVAR(CLASSPATH) REPLACE(*YES) VALUE(' +
            qte +
            '/java/tweetme4i' +
            ':/java/tweetme4i/TweetMe4i.jar' +
            ':/java/tweetme4i/twitter4j-core-2.2.5.jar' +
            qte + ')';

         QCMDEXC(%trimr(cmd): %len(%trimr(cmd)) );

         cmd = 'ADDENVVAR ENVVAR(QIBM_RPG_JAVA_PROPERTIES) ' +
           'REPLACE(*YES) VALUE(' + qte + '-Djava.version=1.5;' + qte + ')';

         QCMDEXC(%trimr(cmd): %len(%trimr(cmd)) );
       on-error;
       endmon;
       
       gSrchStr = 'from:aaronbartell since:2011-10-01';
       jStr = TweetMe4i_search( newStr(gSrchStr) );
       gResult = getBytes(jStr);
       
       if gResult.code = 'SUCCESS';
         jsonToDB(gResult.text);
       endif;

En el Listado 3 puse en negrito las áreas que discutiremos. En primer lugar veremos la variable de entorno CLASSPATH siendo añadida para incluir TweetMe4i.jar y twitter4j-core-2.2.5.jar. El TweetMe4i.jar contiene la función search() discutida anteriormente y twitter4j-core-2.2.5.jar es la más reciente versión de Twitter4j a la fecha de este artículo. A continuación, mire la formulación de la cadena de caracteres de búsqueda que se aplica a la variable gSrchStr que entonces se utiliza en la llamada a TweetMe4i_search(). El prototipo de RPG para el API TweetMe4i_search puede visualizarse en el Listado 4.

Listado 4. Prototipo de TweetMe4i_search
D TweetMe4i_search...
D                 pr              o   class(*java: jStrConst) static
D                                     extproc(
D                                     *java:
D                                     'com.mowyourlawn.twitter.TweetMe4i':
D                                     'search')
D  pTxt                           o   class(*java: jStrConst) const

Después que el programa RPG recibe de vuelta la respuesta de JSON, el último bit de código importante en el Listado 3 es la llamada a jsonToDB(). El subprocedimiento jsonToDB() puede visualizarse en el Listado 5 y su propósito es tomar la cadena de caracteres JSON introducida, analizarla y escribir los contenidos en una tabla DB2, TWTHST (abreviación de Tweet History).

Listado 5. Subprocedimiento jsonToDB
 P jsonToDB        b
 D jsontoDB        pi
 D  pStr                      65535a

 D jRoot           S               *
 D jTweets         S               *
 D jObj            S               *
 D tweetCount      S             10i 0
 D x               S             10i 0
  /free

   jRoot = json_parse(%addr(pStr));

   jTweets = json_getArray(jRoot: 'tweets');
   tweetCount = jsona_size(jTweets);

   for x = 0 to (tweetCount - 1);
     jObj = jsona_getObject(jTweets: x);

     if jObj = *null;
       leave;
     endif;

     clear TWTHSTR;
     ID = json_getLong(jObj: 'id');
     chain ID TWTHST;
     if not %found(TWTHST);
       TXT = %str( json_get(jObj: 'text'));
       FRMUSRID = json_getInt(jObj: 'from_user_id');
       FRMUSR = %str( json_get(jObj: 'from_user'));
       CRTDAT = %str( json_get(jObj: 'created_at'));
       write TWTHSTR;
     endif;
   endfor;

   json_dispose(jRoot);

  /end-free
 P                 e

Este subprocedimiento introduce el objeto JSON *SRVPGM de Mihael Schmidt de RPGNextGen.com. Todas las llamada del subprocedimiento que comiencen con json_ o jsona_ son del JSON *SRVPGM de Mihael y las variables que empiecen con una j minúscula, se supone que representan los objetos de JSON *SRVPGM (punteros, realmente). Definitivamente, usted debe visitar RPGNextGen.com si aún no lo ha hecho. Mihael ha estado muy ocupado y ha sido generoso con la comunidad RPG con sus muchas herramientas de fuente abierta.

El primer paso en el subprocedimiento jsonToDB es llamar la rutina json_parse() para, en segundo plano, tomar la cadena de caracteres JSON y almacenarla en un array de punteros especializados. Esta operación permite al programa RPG acceder más tarde a las distintas partes de JSON por su nombre. El código utiliza json_getArray() para obtener la porción tweets del array y almacena una referencia para ella en el puntero jTweets – si es necesario, vuelva al Listado 2 para una revisión de la estructura. Después de obtener el número total de tweets con jsona_size(), la lógica del código empieza a iterar los resultados empezando por un índice de cero. El colaborador de código abierto, Mihael, debe haber tenido Java en la mente el día que creó esta parte de la herramienta – ¡todos sabemos que a la gente de RPG le gusta empezar los índices en 1! La llamada a jsona_getObject() recupera una iteración de tweets y la almacena en jObj. Después de determinar si o no el jObj es nulo (p. ej., ¿fue la recuperación satisfactoria? y ¿existía la entrada?), el código empieza la obtención de las diversas partes del resultado de tweets de JSON mediante llamadas a la API json_ y llenándolas en el registro de DB2. Si explora en los prototipos json_ encontrará que hay "getters" genéricos como json_get(), y otros más específicos como json_getString() o json_getInt(). Cualquier enfoque funciona bien, aunque los más genéricos requieren una conversión de tipos como se muestra (p. ej., %str() ).

La definición de la tabla TWTHST se muestra en el Listado 6. Las columnas en TWTHST están ocupadas con los datos de Twitter, incluyendo la clave única de la tabla. Los valores de las etiquetas de las columnas corresponden al nombre real de la entidad JSON que Twitter y Twitter4j proporcionan.

Listado 6. Definición de la tabla TTHST
	CREATE TABLE TWEETME4I.TWTHST (
  ID NUMERIC(30,0) NOT NULL DEFAULT 0 ,
  TXT CHAR(140) CCSID 37 NOT NULL DEFAULT '' ,
  FRMUSRID NUMERIC(9, 0) NOT NULL DEFAULT 0 ,
  FRMUSR CHAR(20) CCSID 37 NOT NULL DEFAULT '' ,
  CRTDAT CHAR(31) CCSID 37 NOT NULL DEFAULT '' ,
  PRIMARY KEY( ID ) );

LABEL ON COLUMN TWEET4MEI.TWTHST
(    ID TEXT IS 'ID' ,
	TXT TEXT IS 'TEXT' ,
	FRMUSRID TEXT IS 'FROM_USER_ID' ,
	FRMUSR TEXT IS 'FROM_USER' ,
	CRTDAT TEXT IS 'CREATED_AT' ) ;

El último paso necesario en jsonToDB() es limpiar toda la memoria asignada llamando a json_dispose(). En este punto, la codificación está completa y ahora hay resultados en la tabla DB2, TWTHST, como se muestra en la Figura 1 mediante una captura de pantalla de Squirrel SQL (una excelente herramienta para comprobar si usted aún no la usa).

Figura 1. Contenido de TWTHST mediante Squirrel SQL
Contenido de TWTHST mediante Squirrel SQL

Resumen

¡Eso es todo! Usted ha hecho oficialmente una búsqueda Twitter desde su IBM i y almacenado los resultados en nuestro querido DB2. Observe que también hay APIs para las otras redes sociales como LinkedIn y Facebook, pero que a su vez requieren más permisos para ver el contenido que se envía o recibe (es decir, en Facebook usted debe ser amigo de alguien para ver su contenido). Si encuentra útil ver una API para Facebook o LinkedIn, envíeme un email y veré lo que es necesario para preparar algo y, futuramente, escribir sobre ello.


Recursos

Comentarios

developerWorks: Ingrese

Los campos obligatorios están marcados con un asterisco (*).


¿Necesita un IBM ID?
¿Olvidó su IBM ID?


¿Olvidó su Password?
Cambie su Password

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


La primera vez que inicie sesión en developerWorks, se creará un perfil para usted. La información en su propio perfil (nombre, país/región y nombre de la empresa) se muestra al público y acompañará a cualquier contenido que publique, a menos que opte por la opción de ocultar el nombre de su empresa. Puede actualizar su cuenta de IBM en cualquier momento.

Toda la información enviada es segura.

Elija su nombre para mostrar



La primera vez que inicia sesión en developerWorks se crea un perfil para usted, teniendo que elegir un nombre para mostrar en el mismo. Este nombre acompañará el contenido que usted publique en developerWorks.

Por favor elija un nombre de 3 - 31 caracteres. Su nombre de usuario debe ser único en la comunidad developerWorks y debe ser distinto a su dirección de email por motivos de privacidad.

Los campos obligatorios están marcados con un asterisco (*).

(Por favor elija un nombre de 3 - 31 caracteres.)

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


Toda la información enviada es segura.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=90
Zone=tecnologia Java
ArticleID=822437
ArticleTitle=Tome todas las precauciones con TweetMe4i y JSON
publish-date=06252012