JDC Tech Tips (22 de Enero de 2002)

Bienvenido a los Consejos Técnicos de la Conexión del Desarrollador Java (JDC), del 22 de Enero de 2002. Esta edición cubre:

  • Recuperar Mail con el API JavaMail.
  • Trabajar con el API Java Communications (puertos serie y paralelo).

Estos consejos fueron desarrollados usando Java(tm) 2 SDK, Standard Edition v 1.3

Se puede ver esta edición (en su original en inglés) de los Consejos Técnicos en formato html en http://java.sun.com/jdc/JDCTechTips/2002/tt0122.html

Recuperar Mail con el API JavaMail

El API JavaMail proporciona el marco de trabajo para enviar y recibir mensajes electrónicos (email). El JDC Tech Tip "Enviar Mail con el API JavaMail" nos mostró como enviar mail mediante SMTP a través del API JavaMail. En este truco, veremos cómo recuperar mensajes de nuestro servidor POP/IMAP.

En muchas cosas recuperar mensajes es similar a enviarlos. Por ejemplo, enviar mail implica usar las clases Session, Message, Address, y Transport. Recuperar mensajes implica las mismas clases Session y Message, sin embargo también usamos las clases Folder y Store. Una vez hecha una conexión con el servidor de correo para recuperar mensajes, los mensajes son almacenados en un Folder del Store.

Lo primero que hacemos para recuperar mail es conectar con el servidor de correo, como lo hicimos al enviar. Pero los servidores de correo son diferentes. Cuando enviamos mail, conectamos a un servidor que soporte el protocolo Simple Mail Transfer Protocol (SMTP). Este es un protocolo explícito para enviar correo electrónico. Cuando recuperamos el correo, conectamos a un servidor que soporte los protocolos Post Office Protocol, Version 3 (POP3) o Internet Message Access Protocol, Version 4 (IMAP4). Estos protocolos están diseñados para recuerar correo electrónico. POP es un protocolo sencillo. Permite al usuario recuperar el correo, pero no tiene la sofisticación para hacer cosas como identificar el nuevo correo. En comparación IMAP,es más sofisticado.

Podemos obtener una sesión con los métodos getDefaultInstance() o getInstance() de Session. Llamar al método getDefaultInstance() devuelve un ejemplar de sesión compartida. Esto significa que la misma sesión es devuelta (y así es compartida) por toda llamada al método. El método getInstance() devuelve un nuevo ejemplar de sesión cada vez que lo llamamos. Las sesiones nuevas son útiles si no queremos que otros threads trabajen conjuntamente con la misma sesión compartida.

Cuando obtengamos la sesión, debemos pasarle un ejemplar de Properties. Este contiene las selecciones de propiedades como el servidor de mail que estámos usando para la conexión. Necesitamos selecionar el "mail.pop3.host" (o "mail.imap.host") para el servidor de mail de la conexión (por ejemplo, pop.example.com):

// Setup properties
Properties props = System.getProperties();
props.put("mail.pop3.host", host);

Cuando enviamos mail, debemos autentificar la conexión, por ejemplo, pedir un nombre de usuario y una password. Podemos hacer esto extendiendo la clase Authenticator de JavaMail. Por ejemplo, la siguiente clase, PopupAuthenticator, usa un JOptionPane Swing para pedir un nombre de usuario y una password. En este ejemplo, el usuario introducirá el nombre de usuario y la passwrod como una lista separada por comas. Observa que el método getPasswordAuthentication() devuelve el nombre de usuario y la passwod. (Sientete libre para mejorar esto usando un JPasswordField para la password).

import javax.mail.*;
import javax.swing.*;
import java.util.*;

public class PopupAuthenticator 
    extends Authenticator {

  public PasswordAuthentication 
      getPasswordAuthentication() {
    String username, password;

    String result = JOptionPane.showInputDialog(
      "Enter 'username,password'");

    StringTokenizer st = 
      new StringTokenizer(result, ",");
    username = st.nextToken();
    password = st.nextToken();

    return new PasswordAuthentication(
      username, password);
  }
}

Después de tener los objetos Properties, y Authenticator, podremos obtener una Session:

// Setup authentication, get session
Authenticator auth = new PopupAuthenticator();
Session session = 
  Session.getDefaultInstance(props, auth);

Luego hacemos una conexión con el Store con el método getStore(), pasandole al método el protocolo de correo apropiado para nuestro servido -- pop3 o imap. Aquí vemos como hacer una conexión para un servidor POP3:

// Get the store
Store store = session.getStore("pop3");
store.connect();

La llamada al método connect() del Store lanza una llamada a PopupAuthenticator. Como se mencionó anteriormente, PopupAuthenticator pide una combinación de nombre de usuario y passwords válidas. Si respondemos con un usuarios válido y la password para la cuenta de correo, se establece una conexión con el servidor de correo y podremos leer nuestro correo.

Todo el correo está almacenado en carpetas, es decir, ejemplares de la clase Folder. Por eso para leer el correo, lo primero que tenemos que hacer es conectar con la carpeta apropiada. En el caso de correo POP, sólo hay una carpeta INBOX. En el caso de IMAP, la caperta puede ser INBOX o cualquiera de las otras carpetas que hayamos creado. Asumiendo que queremos leer el correo de nuestra INBOX, simplemente conectamos con la carpeta con el método getFolder() de Session:

// Get folder
Folder folder = store.getFolder("INBOX");

Luego, necesitamos abrir el Folder con el método open(). Podemos abrirla en modo Folder.READ_WRITE o en modo Folder.READ_ONLY. Para leer mensajes, podemos usar sólo lectura, aunque si queremos borrarlos, necesitamos usar READ_WRITE.

folder.open(Folder.READ_ONLY);

Al conectar con el Folder nos da accedo a los objetos Message individuales. Podemos usar el método getMessage() para obtener un mensajes individual, o como en el siguiente ejemplo, usar el método getMessages() para obtener todos los mensajes:

// Get directory
Message message[] = folder.getMessages();

La clase Folder también define un método getNewMessageCount() para contar el número de nuevos mensajes que hay en el Folder. Sin embargo no deberíamos usarlo en un servidor POP -- recuerda que POP no soporta el concepto de nuevos mensajes.

Tenemos varias opciones en la decisión de qué recuperar de cada mensaje. Por ejemplo, podemos llamar a getFrom() o getSubject() para recuperar la identidad del emisor (como un array de Address), o el subject del mensaje, respectivamente

// Display from (only first) and subject of messages
for (int i=0, n=message.length; i<n; i++) {
  System.out.println(i + ": " 
    + message[i].getFrom()[0] 
    + "	" + message[i].getSubject());
}

La mayoría de las veces estaremos interesados en el contenido del mensaje. Típicamente, usamos el método getContent() para ver el contenido del mensaje.

  System.out.println(message[i].getContent());

Podemos usar el método writeTo() para obtener el contenido del mensaje. Esto nos permite grabar todo el contenido del mensaje (incluyendo cabeceras) en un stream de salida.

Después de leer el correo, debemos asegurarnos de cerrar el Folder y el Store. En el caso del Folder, el método close() requiere que especifiquemos si queremos espurgar cualquier mensaje borrado. El Store no requiere ningún argumento en su método close():

// Close connection 
folder.close(false);
store.close();

Lo que sigue es un programa completo, Fetch, que demuestra el uso de los conceptos descritos hasta ahora. Para poder ejecutar el programa necesitarás tener instalado el API JavaMail, así como el JavaBeans Activation Framework.

El programa Fetch muestra los primeros 200 caracteres de cualquier mensaje actualmente almacenado en nuestro INBOX. Si nuestro servidor soporta IMAP y no POP, debemos cambiar las referencias a "pop3" en el código por "imap". Antes de compilar el programa, recuerda que primero se debe compilar la clase PopupAuthenticator mostrada anteriormente.

Ejecutamos el programa Fetch con un alínea de comandos como ésta:

  java Fetch mailserver

Reemplazamos "mailserver" con el nombre de nuestro servidor de correo.

En respuesta, el programa nos pedirá un identificador de usuario y una password.

import java.io.*;
import java.util.Properties;
import javax.mail.*;
import javax.mail.internet.*;

public class Fetch {
  public static void main (String args[]) 
      throws Exception {
    String host = args[0];

    // Get system properties
    Properties props = System.getProperties();
    props.put("mail.pop3.host", host);

    // Setup authentication, get session
    Authenticator auth = new PopupAuthenticator();
    Session session = 
      Session.getDefaultInstance(props, auth);

    // Get the store
    Store store = session.getStore("pop3");
    store.connect();

    // Get folder
    Folder folder = store.getFolder("INBOX");
    folder.open(Folder.READ_ONLY);

    // Get directory
    Message message[] = folder.getMessages();
    for (int i=0, n=message.length; i<n; i++) {

       System.out.println(i + ": " 
         + message[i].getFrom()[0] 
         + "	" + message[i].getSubject());
       String content = 
         message[i].getContent().toString();
       if (content.length() > 200) {
         content = content.substring(0, 200);
       }
       System.out.print(content);
    }

    // Close connection 
    folder.close(false);
    store.close();
    System.exit(0);
  }
}

La última versión del API JavaMail API está disponible para su descarga desde la página JavaMail API. Para usar el API JavaMail, también debes tener instalado el JavaBeans Activation Framework. Éste está disponible para descarga desde la página JavaBeans Activation Framework. También puedes obtener el API JavaMail API y el JavaBeans Activation Framework como partes de la Java 2 Platform, Enterprise Edition 1.3 . El código fuente de las clases JavaMail está disponible a través del J2EE 1.3 Sun Community Source Licensing (SCSL) program.

Aquí hay una variación de la aproximación anterior. Si no queremos usar un Authenticator, obtenemos una Session sin seleccionar ninguna propiedad. Luego proporcionamos el nombre del host, el nombre de usuario y la password al método connect(). El siguiente fragmento muestra este comportamiento:

// Setup empty properties
Properties props = new Properties();

// Get session
Session session = Session.getDefaultInstance(props, null);

// Get the store
Store store = session.getStore("pop3");
store.connect(host, username, password);

Observa que el ejemplo Fetch no trata con ningún mensaje que contenga un attachment. Para información sobre como obtener attachments, puedes visitar Fundamentos del API JavaMail.

También, si usas Yahoo para el correo, debes activar POP Access & Forwarding desde su pantalla Options para poder obtener el correo a través del API JavaMail. Creo que no puedes usar Hotmail -- no soporta acceso remoto.

Trabajar con el API Java Communications (puertos serie y paralelo)

El API Java Communications (COMM) es un paquete opcional para la plataforma Java 2. Proporciona soporte para comunicación con dispositivos periféricos a través de los puertos serie y paralelo de un ordenador. Es un API especial en el sentido de que aunque está bien definido multi-plataforma, debes descargar una versión específica de las librerías COMM para utilizarlo realmente.

Este truco presentará el API COMM mostrando cómo obtener una lista de los puertos disponibles en una máquina e imprimiendolos en una impresota. El API COMM no incluye soporte para comunicación sobre puertos Universal Serial Bus (USB) . El soporte para los puertos USB se proporcionara en un API separado que está ahora mismo bajo revisión pública a través del Java Community Process (JCP). Puedes ver la JSR 80 para más detalles.

Para empezar, descarga y descomprime el API Java Communications. Para las plataformas Windows y Solaris puedes visitar Java Communications API. Cuando hagas esto, necesitas un poco de trabajo de configuración. No sólo necesitas poner el fichero comm.jar en tu classpath, aunque este es el primer paso. También necesitas copiar la librería compartida al directorio bin, y el fichero javax.comm.properties al directorio lib del entorno de ejecución. Para Java 2 SDK, versión 1.3 para Windows, esto significa:

copy comm.jar jdk1.3jrelibext
copy win32com.dll jdk1.3in
copy javax.comm.properties jdk1.3jrelib

Después de hacerte trabajo, las clases del API Java Communications están disponibles desde el paquete javax.comm. Las clases princiaples del paquete son CommPortIdentifier y CommPort. Usamos CommPortIdentifier para encontrar el conjunto de objetos CommPort instalados. Luego podemos comunicar individualmente con cada puerto CommPort.

Para encontrar qué puertos hay instaldados, preguntamos al CommPortIdentifier por el conjunto instalado con getPortIdentifiers(). Esto devuelve una Enumeration de objetos CommPortIdentifier. Cada objeto es del tipo PORT_PARALLEL o PORT_SERIAL, dos constantes de la clase CommPortIdentifier.

Para desmostrarlo, el siguiente código muestra el conjunto de puertos disponibles e imprime el nombre y el tipo de cada uno:

import javax.comm.*;
import java.util.Enumeration;

public class ListPorts {
  public static void main(String args[]) {
    Enumeration ports = 
      CommPortIdentifier.getPortIdentifiers();
    while (ports.hasMoreElements()) {
      CommPortIdentifier port = 
        (CommPortIdentifier)ports.nextElement();
      String type;
      switch (port.getPortType()) {
        case CommPortIdentifier.PORT_PARALLEL:
          type = "Parallel"; 
          break;
        case CommPortIdentifier.PORT_SERIAL:
          type = "Serial"; 
          break;
        default:  /// Shouldn't happen
          type = "Unknown"; 
          break;
      }
      System.out.println(port.getName() + ": " + type);
    }
  }
}

ListPorts debería producir un resultado similar al siguiente:

COM1: Serial
COM2: Serial
LPT1: Parallel
LPT2: Parallel

Además de pasear a través de una Enumeration de puertos desde el CommPortIdentifier, podemos solicitar un puerto específico. Hacemos esto pasando el nombre del puerto (LPT1, por ejemplo) al método indentificador getPortIdentifier(). Este devuelve el identificador del puerto, o lanza una javax.comm.NoSuchPortException si el puertono exite.

// Get port
CommPortIdentifier portId = 
  CommPortIdentifier.getPortIdentifier(portname);

Para leer o escribir en un puerto, usamos el método open(). Este método requiere un nombre propio para el puerto y un valor en milisegundos.

// Open port
// Open requires a owner name and timeout
CommPort port = portId.open("Application Name", 30000);

Después de haber abierto el puerto, podemos leer y escribir en el igual que en una conexión socket. InputStream está disponible desde el método getInputStream() de CommPort y OutputStream está disponible con getOutputStream().

// Setup output
OutputStream os = port.getOutputStream();
BufferedOutputStream bos = 
                          new BufferedOutputStream(os);

Usemos el API COMM para imprimir un fichero. Para hacer esto, simplemente buscamos el puerto de la impresora, lo abrimos, obtenemos su OutputStream, y envíamos el contenido del fichero a través de él. El siguiente ejemplo muestra la secuencia. Imprime un fichero de ejemplo PostScript llamado sample.ps. Necesitaremos crear el fichero de ejemplo primero. Asegurate de cerrar el puerto y los streams cuando hayas terminado con él.

import javax.comm.*;
import java.io.*;

public class PrintFile {
  public static void main(String args[]) 
      throws Exception {
    if (args.length != 2) {
      System.err.println(
        "usage : java PrintFile port file");
      System.err.println(
        "sample: java PrintFile LPT1 sample.ps");
      System.exit(-1);
    }

    String portname = args[0];
    String filename = args[1];

    // Get port
    CommPortIdentifier portId = 
      CommPortIdentifier.getPortIdentifier(portname);

    // Open port
    // Open requires a owner name and timeout
    CommPort port = portId.open("Application Name", 30000);

    // Setup reading from file
    FileReader fr = new FileReader(filename);
    BufferedReader br = new BufferedReader(fr);

    // Setup output
    OutputStream os = port.getOutputStream();
    BufferedOutputStream bos = new BufferedOutputStream(os);

    int c;
    while ((c = br.read()) != -1) {
      bos.write(c);
    }

    // Close
    bos.close();
    br.close();
    port.close();
  }
}

Para más información sobre el API Java Communications, puedes ver la Java Communications API Users Guide.

Copyright y notas de la traducción

Nota respecto a la traducción

El original en inglés de la presente edición de los JDC Tech Tips fue escrita por Glen McCluskey, la traducción no oficial fue hecha por Juan A. Palos (Ozito), cualquier sugerencia o corrección hágala al correo [email protected] , sugerencia respecto a la edición original a mailto:[email protected]

Nota (Respecto a la edición via email)

Sun respeta su tiempo y su privacidad. La lista de correo de la Conexión del desarrollador Java se usa sólo para propósitos internos de Sun Microsystems(tm). Usted ha recibido este email porque se ha suscrito a la lista. Para desuscribirse vaya a la página de suscripciones, desmarque casilla apropiada y haga clic en el botón Update.

Suscripciones

Para suscribirse a la lista de correo de noticias de la JDC vaya a la página de suscripciones, elija los boletines a los que quiera suscribirse, y haga clic en Update.

Realimentación

¿Comentarios?, envie su sugerencias a los Consejos Técnicos de la JDC a mailto:[email protected]

Archivos

Usted encontrará las ediciones de los Consejos Técnicos de la JDC (en su original en inglés) en http://java.sun.com/jdc/TechTips/index.html

Copyright

Copyright 2001 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Este documento esta protegido por las leyes de autor. Para mayor información vea http://java.sun.com/jdc/copyright.html

Enlaces a sitios fuera de Sun

Los Consejos Técnicos de la JDC pueden dar enlaces a otros sitios y recursos. Ya que Sun no tiene control sobre esos sitios o recursos usted reconoce y acepta que Sun no es responsable por la disponibilidad de tales sitios o recursos, y no se responsabiliza por cualquier contenido, anuncios , productos u otros materiales disponibles en tales sitios o recursos. Sun no será responsable, directa o indirectamente, por cualquier daño o pérdida causada o supuestamente causada por o en relación con el uso de o seguridad sobre cualquier tal contenido, bienes o servicios disponibles en o através de cualquier sitio o recurso.

El original en Ingles de esta edición de los Consejos técnicos fue escrita por Glen McCluskey.

JDC Tech Tips January 22, 2002

Sun, Sun Microsystems, Java y Java Developer Connection (JDC) son marcas registradas de Sun Microsystems Incs. en los Estados Unidos y cualquier otro país.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
ARTÍCULO ANTERIOR

SIGUIENTE ARTÍCULO